如何使用EF实现聚合根存储库添加子实体

时间:2012-02-13 16:09:38

标签: asp.net-mvc entity-framework domain-driven-design repository-pattern aggregateroot

我正在开发一个MVC应用程序。我有一个域模型,我使用repositry模式进行数据访问和Entity Framework Code First。我还有一个UnitOfWork类,我通过它调用存储库操作。

当我尝试利用聚合根并通过父存储库处理子对象时,我的问题主要出现了。

这是问题所在: 父类“供应商”与部门有多个合同。在这种情况下,我选择让合同成为供应商的子女。

要添加新合约,我需要添加一个方法来在我的SupplierRepository中添加合约,我试过:

 public class SupplierRepository : GenericRepository<Supplier> 
        {

            public SupplierRepository(MyContext context) 
            : base(context)
            {
            }

            public void AddSupplierContract(SupplierContract contract)
            {
                 var supplier = context.Suppliers.Find(contract.SupplierId);
                 supplier.Contract.Add(contract);

            }

我也尝试过:

            public void AddSupplierContract(SupplierContract contract)
            {
                context.Entry(contract).State = EntityState.Added;
            }

         }

当我打电话

_unitOfWork.save();

我收到错误告诉我:

  

IEntityChangeTracker的多个实例

无法引用实体对象

UnitOfWork实现我的DbContext(myDbContext)和我的SupplierRepository并调用myDbContext.Save()

  1. 为什么我会这样做
  2. 我应该如何实现聚合根存储库(子对象的CRUD操作)
  3. 据我所知,我应该在存储库中有一个方法来获取合同并添加它,而不是在我的MVC应用程序的Controller中执行此操作,但我似乎没有让它工作。

    我已经看到了很多关于聚合根的信息,但没有关于如何实现它的例子。

    感谢。

    解决方案:

    好吧,我终于明白了。

    因此,存储库不存在问题,但新的SupplierContract向商店查询了创建它的用户实体(通过扩展方法)。显然这个上下文没有处理,因此当我实现它以保存合同实体时,我有两个当前的DbContexts。

    希望有人通过阅读本文来节省时间。

    我通过在SupplierRepository中这样做解决的聚合根存储库:

        public void AddSupplierContract(SupplierContract contract)
        {
            db.SupplierContracts.Add(contract);
        }
    

    并调用UnitOfWork.Save()方法。

2 个答案:

答案 0 :(得分:1)

虽然从技术上讲你可能已经解决了这个问题,但我希望你知道你的设计中存在一些根本性的缺陷(除非你使用Fowler存储库):存储库(DDD类)处理聚合只要。需要将SupplierContract添加到上下文中的事实不是调用代码的关注点。那么,为什么要暴露这种方法?我还会重新考虑让存储库委派保存(为什么还有一个UoW)。就聚合物而言,我感觉你似乎将它们视为结构对象,而不是行为对象。因此,你似乎陷入了痛苦的世界,经历了一些动作,但没有获得任何价值。

答案 1 :(得分:0)

要消除该错误,您应该使用相同的MyContext实例来创建所有存储库。如果使用某个dependency-injector,它应该允许您通过单个请求配置相同的MyContext对象。例如,对于Ninject,那将是

kernel.Bind<MyContext>().ToSelf().InRequestScope();