2

从存储库中删除模型(聚合根)时,还必须删除所有关联的聚合。存储库模式:删除聚合根

我挣扎在我的实体框架6实现存储库模式

在我的例子来实现这一点,我想从CustomerRepository删除Customer。所有客户的Order对象也应该被删除。

库(精简):

public interface IRepository<T> where T : DomainEntity 
{ 
    void Remove(T item);  
} 

public class EntityFrameworkRepository<T> : IRepository<T> where T : DomainEntity 
{ 
    private readonly DbSet<T> dbSet; 
    public DbContext context; 

    public EntityFrameworkRepository(IUnitOfWork unitOfWork) 
    { 
     context = entityFrameworkUnitOfWork.context; 
     dbSet = dbSet = context.Set<T>(); 
    } 

    public virtual void Remove(T item) 
    { 
     DbEntityEntry dbEntityEntry = context.Entry(item); 

     if (dbEntityEntry.State == EntityState.Detached) 
     { 
      dbSet.Attach(item); 
     } 

     dbSet.Remove(item); 
    } 
} 

public class EntityFrameworkUnitOfWork : IUnitOfWork 
{ 
    public readonly DbContext context; 

    public EntityFrameworkUnitOfWork() 
    { 
     this.context = new ReleaseContext(); 
    } 

    public void Commit() 
    { 
     context.SaveChanges(); 
    } 
} 

ICustomerRepositoryCustomerRepository(EF实现):

public interface ICustomerRepository : IRepository<Customer> 
{ 
    IEnumerable<Customer> GetAllActive(); 
} 

public class CustomerRepository : EntityFrameworkRepository<Customer>, ICustomerRepository 
{ 
    public CustomerRepository(IUnitOfWork unitOfWork) 
     : base(unitOfWork) 
    { } 

    public override void Remove(Order item) 
    { 
     item.Orders.Clear(); 

     base.Remove(item); 
    } 
} 

客户端代码:

customerRepository.Remove(customer); 
unitOfWork.Commit(); 

抛出异常:

System.InvalidOperationException:操作失败: 关系不能被改变,因为一个或多个 外键的属性是不可为空。当对 关系进行更改时,相关的外键属性将设置为空值。 如果外键不支持空值,则必须定义新的关系 ,必须为外键属性指定另一个非空值,或者必须删除不相关的对象。

我会除了呼吁item.Orders.Clear()向EF表明,必须删除关联。

+0

*“所有客户的订单对象也应该删除。”*哇!想一想...一个订单因为客户被删除而不复存在?即使是历史订单?应该删除客户更改历史记录吗?在我看来,“秩序”也应该是一个聚合根,至少在一种情况下。 – MattDavey

+0

@MattDavey:对不起,我应该提到这是示例代码。一个坏例子,正如你所指出的那样。 – davenewza

+1

我不相信真正的会更好。硬删除不仅仅是一种DDD方式。 –

回答

1

一些模式有一个很好的做法:不要删除任何东西: ) 而是将其标记为“已删除”。

因为为什么?告诉我们一个真实的业务需求物理删除的东西? 不仅它减慢了速度(通常DB在删除时锁定很多),导致碎片等,但在大多数情况下,这是荒谬的!没有生意可以让你实际删除客户和订单清单!

业务不会删除任何内容。在真正的企业中,没有人会去查找与特定客户有关的所有文件,并将其丢弃在碎纸机中。除非他们做了违法的事和联邦调查局正在敲门:)

谈谈你的业务专家,谁知道一些关于电脑(这是真正的业务专家)。他们会告诉你,当客户停止成为客户时(或许他们被“归档”,也许还有别的东西,或者甚至没有),然后对其进行建模,会发生什么。 这就是我们程序员通常发明的“删除”东西的概念。

此外,分析历史信息在未来的某个时间可能会非常有用!

只有两个选择,当物理删除的可能是必要的:

  1. 以节省磁盘空间(这是不是一个问题了,当磁盘空间如粪土一样便宜)
  2. 有一定的法律义务在客户希望删除数据时删除数据(这是非常罕见的要求,通常在某些域中得到满足)。

对于#1,空间现在不再是问题,所以实施删除可能会比从中受益更多。 对于#2,无论如何你都想要明确,你可能会以不同的方式管理你的数据存储。例如,您可能希望有每个客户端数据库,然后使你能把数据库和所有备份遵守法规(是的,你必须删除备份,以便在法律上说,你不持有删除的数据了)

那么,哪种情况是你的?为什么要删除,你是真实的业务要求?

2

该错误表明您的清除方法没有删除子实体。
您是否知道关于删除的流畅的api附加级联?

HasRequired(t => t.Parent).WithOptional()。WillCascadeOnDelete(true);

所以如果你删除一个根对象,所有的依赖项可以被Db删除。 虽然这种选择并不总是可用...

由于您使用的IRepository ... 你考虑使用像

public int DeleteWhere(Expression<Func<TPoco, bool>> predicate) { 
     var delList = Context.Set<TPoco>().Where(predicate); 
     foreach (var poco in delList) { 
      SetEntityState(poco, EntityState.Deleted); 
     } 
     return delList.Count; 

    } 

var custid = 1; 
var RepOrder - new Respository<Order>(); 
var delcnt = RepOrder.DeleteWhere(t=>t.CustomerId == custid); 

MYContext.SaveChanges()