cfs
cfs

Reputation: 1324

How to implement Aggregate Root repository an add child entity with EF

I'm developing an MVC application. I have a Domain Model, and I use a repositry pattern for data access and Entity Framework Code First. I also have a UnitOfWork class which I call the repository operations through.

My problem mainly arises when I try to take advantage of aggregate roots and handle child objects through their parent repository.

This is the problem: Parent class "Supplier" has several Contracts with Departments. I've chosen to make the contract a child of Supplier in this case.

To add a new contract I need to add a method to add a contract in my SupplierRepository, I tried:

 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);

            }

And I also tried:

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

         }

When i call

_unitOfWork.save();

I get an error telling me:

An entity object cannot be referenced by multiple instances of IEntityChangeTracker

UnitOfWork instansiates my DbContext (myDbContext) and my SupplierRepository and calls the myDbContext.Save()

  1. Why do I get this behavior
  2. How should I implement an Aggregate Root Repository (CRUD operations for the child objects)

As far as I understand I should have a method in the repository that takes a contract and adds it, and not do this in the Controller of my MVC app, but I don't seem to get it working.

I've seen a lot of information about Aggregate Roots, but no examples of how to implement it.

Thanks.

Solution:

Well I finally figured it out.

So it was not a problem with the repository, but the new SupplierContract queryed the store for the user entity that created it (through an extension method). Obviously this context did not dispose and therefore i had two current DbContexts when I instansiated it to save the contract entity.

Hopefully someone saves time by reading this.

The Aggregate Root repository I solved by just doing like this in the SupplierRepository:

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

And calling UnitOfWork.Save() method.

Upvotes: 0

Views: 2719

Answers (2)

Yves Reynhout
Yves Reynhout

Reputation: 2990

While technically you may have solved this issue, I do hope you are aware there's something fundamentally flawed in your design (unless you're using Fowler repositories): repositories (the DDD kind) deal in aggregates only. The fact that SupplierContract needs to be added to the context is not a concern of the calling code. So, why expose that method? I would also reconsider having the repository delegate the save (why else have a UoW). As far as aggregates are concerned I get the feeling you seem to be treating them as structural objects, not as behavioral ones. Hence you seem to be in for a world of pain, going through some of the moves, but not getting any of the value.

Upvotes: 2

archil
archil

Reputation: 39501

To get rid of that error, you should use same MyContext instance to create all the repositories. If you use some dependency-injector, it should allow you to configure same MyContext object through single request. For example, for Ninject, that would be

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

Upvotes: 0

Related Questions