2

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

我正在努力在我的存储库模式的实体框架 6 实现中实现这一点

在我的示例中,我想CustomerCustomerRepository. 所有客户的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 表明必须删除这些关联外,我会。

4

2 回答 2

2

该错误表明您的 clear 方法没有删除子实体。
您是否知道删除时流利的 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()
于 2013-12-12T11:28:12.923 回答
1

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

因为为什么?向我们展示实际删除内容的真实业务需求?它不仅会减慢速度(通常数据库在删除时会锁定很多),导致碎片等,而且在大多数情况下它是荒谬的!没有企业允许您实际删除客户和订单列表!

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

与对计算机稍有了解的业务专家交谈(这些是真正的业务专家)。他们会告诉你当客户不再是客户时会发生什么(也许他们被“归档”了,也许是别的东西,或者什么都没有),然后对其进行建模。是我们,程序员,通常发明“删除”东西的概念。

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

当需要物理删除时,只有两个选项:

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

对于#1,空间现在不是问题,因此实施删除可能会花费更多而不是从中受益。对于#2,无论如何您都希望明确,并且您可能会以不同的方式管理数据存储。例如,您可能希望每个客户端都有一个数据库,这样您就可以删除数据库和所有备份以符合规定(是的,您必须删除备份才能合法地表示您不再保留已删除的数据)

那么你的情况是什么?为什么要删除,您真正的业务需求是什么?

于 2013-12-14T03:38:32.500 回答