Pregunta

I'm writing an ORM and am unsure of the expected behaviour of the Repository, or more precisely, the frontier between the Repository and the Unit Of Work. From my understanding, a Repository might look like this:

interface IPersonRepository
{
    public function find(Criteria criteria);
    public function add(Person person);
    public function delete(Person person);
}

According to Fowler (PoEAA, page 322):

A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. [...] Objects can be added to and removed from the Repository, as they can from a simple collection of objects.

This would imply that the following test should work (assuming that we already have a Person persisted, whose last name is Fowler):

collection = repository.find(lastnameEqualsFowlerCriteria);
person = collection[0];

assertEquals(person.lastname, "Fowler");

person.lastname = "Evans";
newCollection = repository.find(lastnameEqualsFowlerCriteria);

assertFalse(newCollection.contains(person));

That means that when mapping to a database, even if no explicit save() method has been called somewhere, the Person model must have been automatically persisted by the Repository, so that the next query returned the correct collection, not containing the original Person.

But, isn't that the role of the Unit Of Work, to decide which model to persist to the database, and when?

In the above implementation, the Repository has to decide to persist the Person previously retrieved when receiving another find() call, so that the result is consistent with the modification. But if no other find() call were issued, the model would not have been persisted implicitly at all.

In the context of a Unit Of Work, it is not really a problem, because we can start a transaction at the beginning, and rollback any insert to the db anyway if needed. But when used alone, can't this Repository lead to unexpected, unpredictable behaviour?

¿Fue útil?

Solución

A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. [...] Objects can be added to and removed from the Repository, as they can from a simple collection of objects.

This does not mean you do not need a save method. You still need to explicitly commit your changes to storage.

See The Unit Of Work Pattern And Persistence Ignorance

public interface IUnitOfWork {
  void MarkDirty(object entity);
  void MarkNew(object entity);
  void MarkDeleted(object entity);
  void Commit();
  void Rollback();
}

In a way, you can think of the Unit of Work as a place to dump all transaction-handling code. The responsibilities of the Unit of Work are to:

  • Manage transactions.
  • Order the database inserts, deletes, and updates.
  • Prevent duplicate updates. Inside a single usage of a Unit of Work object, different parts of the code may mark the same Invoice object as changed, but the Unit of Work class will only issue a single UPDATE command to the databas

Otros consejos

I think what you;re asking about is following: http://martinfowler.com/eaaCatalog/identityMap.html

Repository should keep fetched objects in memory and all subsequent calls for that entity should not be retrieved from persistence storage, hence your example should work fine.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top