Using The Repository Pattern, Is It Best To Save P

2019-01-24 17:13发布

问题:

Having a parent object Employee with a list of Address child objects:

class Employee
{
    List<Address> addresses;
}

and a Repository method:

void Insert(Employee);

Should the code within this repository attempt to save the parent Employee as well as the child Address objects, or should separate repositories handle the parent and children objects?

If separate repositories, then when saving the Employee object and its children within the client code, should this be separate calls at that level, combined in some sort of service or is there another alternative?

回答1:

The repository should handle the entire aggregate object (parent and all children), because that's what makes it a repository. If you're saving root and child objects separately, then the pattern you're using isn't really called a repository (although it might still be a perfectly good solution)

"Repository" is just a convenient name for a particular data access pattern that loads and saves entire aggregates in one go - so when you say to another developer that you're using the repository pattern, they know that that's what's going on.



回答2:

There is two kind of links between entities.

One is referencing: when one entity contains reference to another. That entities are independent and any of them can be combined with another appropriate entity of that type.

For example: customer and product, user and address etc.

Another type is aggreagting: when few entities represents the single object that for some reasons is stored in few tables/split over few classes. But it stills to be a single object: one part has no sense without other, and cannot be combined with other entity. One entity in this case is always major, and deleting the major always causes deleting aggregated entities.

For example: order and order items, house and it's rooms etc.

Referencing represents relation, aggregation represents owning.

SO Saving of entity with reference should not save referenced entity (except case of referenced entity is new, but in this case it is preferred to save referenced entity before).

Saving entity with aggregates must save aggregated entities. In single transaction. Because this is a single object. Also it is preferred to not allow saving of aggregates separately (only if performance is very critical) - otherwise you would get a lot of problems with concurrency.



回答3:

I would try and go with a Unit of Work pattern where you open, make changes, commit, and then it just figures out the right thing to do.

If you're in a relational database, you'll end up with something like Hibernate having a mapper per table. If you are in a non-relational database, you might have to get creative, and mark domain objects as IAggregateRoot or something, to know which ones have their own repositories and which don't.

For example, if Employees are stored in one SOA, and Addresses in another, they'd each be IAggregateRoots, and ideally the Unit of Work would automatically hand each of the dirty instances off to its corresponding repository for saving.

So then its transparent to client code, but not a useless layer of indirection (like services mostly are, in the java world anyway--not always, but the ones I've seen).

I love DDD, but I think it over-hypes repositories, and, empirically, causes a lot of confusion because people are always asking how to do them correctly.

Unless I had a system with known multiple SOA-based backends (and not just "hey, we might be Amazon someday and need that"), I would shy away from repositories, personally. Hibernate-based mappers/DAOs/something, sure, but they seem simpler and more concrete than repositories.



回答4:

I prefer a repository per table but glue them together into an aggregate repository:

public RootEmployeeRepository (
  IEmployeeRepository employeeRepository, 
  IAddressRepository addressRepository)
{
  // init
}

public SaveEmployee (Employee employee)
{
  // call IEmployeeRepository to save the employee record minus childen
  // call IAddressRepository to save employee.addresses
  // commit all changes to the DB via UnitOfWork
}


回答5:

I prefer NHibernate which handles cascading saves for you.