EF - Persistence Ignorance for Detach object - Best Practice

235 Views Asked by At

Nowdays I cannot understand at all how the persistence ignorance could be applied with entity framework. I've a classic repository and unit of work design by using entity framework.

Now, imagine a simple client side scenario where I need to read some object list, and later saving one of them. My entity contains some object graph, for instance, the Person entity coontains Address complex property where Addrress is another entity and also a list of Hobby objects, where it also is another entity. My client:

var personList = PersonRepository.GetAll();
PersonRepository.Dispose(); // it will dispose EF's ObjectContext 
var person = personList[0];
person.Address.City = "...";
person.Hobby.Remove(person.Hobby.First());
PersonRepository.SaveChanges(person);

As you can see, I've mantained the persistence ignorance logic, I'm limited to use person object only and its boundaries, however, in real world, tha above code snippet will be inclined to fail for detach object beacuse I've disposed the unit of work.

So, I've thought to use some entity wrapper with some method like ManageGraph(object obj, ObjectState state) in order to preserve any other change in a internal dictionary for all relations changed. However, I don't like this solution, it seems too dirty and looks like anty pattern:

person.Name = "some name";
person.ManageGraph(AddressObject, state.Modified);
rather then
person.ManageGraph(AddressObject, state.Added);

But...Where is the persistence ignorance? Why I'm enforce to use bad tricks in order to get the right work? Persistence ignorance means that I must treat the simple object without any other stuff, so it would be like following:

person.SomeProperty = SomeValue
person.ComplexProperty.OtherProperty = otherValue
person.ListOfComplexProperty.Add(new entity);

For sure, I know, I don't want the magic solution, it doesn't exist, but, is there some good solution or suggestion to get best work?

1

There are 1 best solutions below

0
On

You are not detaching your entity, you are just disposing the context. It means your entity is no more "change-tracked" by any valid context. When you call the SaveChanges method from a new context, the operation fails and you get no exception (that's okay because the entity is in memory but it is no tracked by anyting at all, for the new context, it does not exist). You should Detach the entity before disposing the context, and then, when exiting the method, Attach it back to the new context. If you are working with DbContext, maybe you should look at this article.

Nevertheless, Persistence Ignorance is a guideline. With actual languages, it is almost impossible to reach. Your best friends are the Repository Pattern and the Unit Of Work. They will decouple your business code from the context by implementing an abstraction, and "hide" this persistence related stuff to the business code. I suggest you should not care about detaching your entities in your business code. If you absolutely need it (?), maybe you should do it at the repository level. Managing the context lifecycle from within the business code is a bad approach, you should keep this logic in your repo/UoW layer.

Hope this helps,