Reputation: 1324
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()
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
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
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