存储库模式:删除聚合根

时间:2013-12-12 09:31:40

标签: entity-framework domain-driven-design repository-pattern unit-of-work onion-architecture

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

我正在努力在我的Entity Framework 6实现存储库模式

中实现它

在我的示例中,我想从Customer中删除CustomerRepository。还应删除所有客户的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:操作失败:   由于一个或多个关系无法改变   外键属性是不可为空的。当对a进行更改时   关系,相关的外键属性设置为空值。   如果外键不支持空值,则为新关系   必须定义外键属性必须另外分配   必须删除非空值或不相关的对象。

我会调用item.Orders.Clear()来向EF表明必须删除关联。

2 个答案:

答案 0 :(得分:2)

错误表明您的明确方法未删除子实体 你知道删除时流畅的api加法级联吗?

  

HasRequired(t =&gt; 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()

答案 1 :(得分:1)

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

因为为什么?向我们展示一个真正的业务需求来物理删除东西? 它不仅会降低速度(通常DB会在删除时锁定很多),导致碎片等,但在大多数情况下它是荒谬的!没有业务可以让您实际删除客户和订单列表!

商家不会删除任何内容。在实际业务中,没有人会找到与特定客户相关的所有文件并将其丢弃在粉碎机中。除非他们做了违法的事情并且FBI正在敲门:)

与熟悉计算机的业务专家(这些是真正的业务专家)交谈。他们会告诉你客户当他们不再是客户时会发生什么(也许他们被“存档”,或许是其他东西,或者可能只是什么),然后对其进行建模。 程序员通常会发明“删除”内容的概念。

此外,分析历史信息在未来的某个时间真的很有帮助!

只有必要进行物理删除时才有两个选项:

  1. 节省磁盘空间(当磁盘空间与污垢一样便宜时,这不再是问题)
  2. 当客户希望删除数据时,要有物理删除数据的法律义务(这是非常罕见的要求,通常在某些域中得到满足)。
  3. 对于#1来说,空间现在不再是一个问题,因此实施删除可能需要花费更多的成本。 对于#2,无论如何你想要显式,你可能会以不同的方式管理你的数据存储。例如,您可能希望每个客户端都有一个数据库,因此您可以删除数据库和所有备份以符合规定(是的,您必须删除备份为了合法地说你不再持有被删除的数据了)

    那你的案件是哪个?为什么要删除,您真正的业务要求是什么?