Entity Framework / Unit of Work Architecture Question
I'm very familiar with UoW, Repository Pattern, etc. but in seeing various implementations of the pattern for Entity Framework, I'm curious why anyone would have a Save or Add method on their repository. If you use the repository to get you a new instance of an object that I would imagine someone would already
public Customer GetNewCustomer()
{
Customer customer = new Customer();
... any initialization code here ...
_context.Customers.AddObject(customer);
return customer;
}
I know开发者_如何学Python in some designs, you can simply use
Customer customer = new Customer();
and its not attached anywhere to the context. However I'm a fan of private constructors so there is a single point of instantiation for a Customer object. With that in mind wouldn't it makes sense to never have an add/save method on the repository when using a UoW pattern and only have this functionality on the IUnitOfWork interface?
When I follow the Spring idiom in Java, units of work (and transactions) are associated with services. They use model and persistence objects to fulfill a request. Transactions are demarked using aspects.
I don't know whether .NET follows a similar idea, but it'd be worth exploring. Have interface-based POCO services and let them own transactions.
I don't think that your solution is correct. That will add empty customer to current unit of work. That means that later code will have a hard time if it decide not to save customer by the current unit of work.
It is quite common that repository have method to save entity. You are combining two patterns used in Domain driven design
- Repository
- Object factory
Repository's responsibility is to retrieve or store entities. Object factory's responsibility is to handle entity construction.
Btw. private constructor of your entity will not be accessible in your repository if repository is not the entity (which would be quite bad).
...wouldn't it makes sense to never have an add/save method on the repository when using a UoW pattern and only have this functionality on the IUnitOfWork interface?
Yes I think it makes sense to only have the Save method on the IUnitOfWork interface. However, I no longer use the repository pattern with EF. Instead, I now use these variations of the command & query patterns.
If you think about it, the EF DbContext is really doing 3 things: 1.) it functions as your repository for reading entity state, 2.) as your repository for mutating entity state, and 3.) as a UnitOfWork for tracking multiple changes and combining them into a single transaction to persist state mutations.
So, why not separate these 3 responsibilities into 3 different interfaces?
public interface IUnitOfWork
{
int SaveChanges();
}
public interface ICommandEntities : IQueryEntities
{
void Create(Entity entity);
void Update(Entity entity);
void Purge(Entity entity);
}
public interface IQueryEntities
{
IQueryable<AggregateRoot1> AggregateRoot1s { get; }
IQueryable<AggregateRoot2> AggregateRoot2s { get; }
IQUeryable<AggregateRootN> AggregateRootNs { get; }
IQueryable<TEntity> EagerLoad<TEntity>(IQueryable<TEntity> query,
Expression<Func<TEntity, object>> expression)
where TEntity : Entity;
}
You can then implement these 3 interfaces on your DbContext class. This keeps the interfaces nice and segregated, and lets you dependency inject only those methods of the DbContext which you need.
For example, your domain should be persistence ignorant, right? In that case, don't give any of your domain classes dependencies on the IUnitOfWork interface. Instead, handle the IUnitOfWork in your IoC composition root (or in an MVC action filter). Then, your query and command handlers deal only with the ICommandEntities and IQueryEntities interfaces.
精彩评论