Change/Status tracking in entity framework 6 - entity-framework

My question relates to overall design within entity framework 6. My model has an entity type called Person. Each person consists of multiple values, some of which it is important that i track the previous values of these properties. An example of that includes Last Interaction Date and Status
The model currently has a separate entity for each property i wish to track historical status on in this case Person_Status and Person_lastInteraction; the relationship is created with a 1 to many relation.
I extend the Person partial class to allow methods for updating the these tracked properties.
....There has to be a better way!
My Concerns:
Every time i want to track a different property i have to create a new entity just for tracking those particular property changes, requiring DB changes
Because EF still exposes the property its possible someone could change the person status without using the methods added to the class.
I'm re-writing a lot of the same exact code to do essentially the same thing
Has anyone encountered a situation as such, what did you do?

Related

Is it possible to tell if an entity is tracked?

I'm using Entity Framework 4.1. I've implemented a base repository using lots of the examples online. My repository get methods take a bool parameter to decide whether to track the entities. Sometimes, I want to load an entity and track it, other times, for some entities, I simply want to read them and display them (i.e. in a graph). In this situation there is never a need to edit, so I don't want the overhead of tracking them. Also, graph entities are sent to a silverlight client, so the entities are disconnected from the context. Hence my Get methods can return a list of entities that are either tracked or not. This is achieved dynamically creating the query as follows:
DbQuery<E> query = Context.Set<E>();
// Track the entities in the context?
if (!trackEntities)
{
query = query.AsNoTracking();
}
However, I now want to enable the user to interact with the graph and edit it. This will not happen very often, so I still want to get some entities without tracking them but to have the ability to save them. To do this I simply attach them to the context and set the state as modified. Everything is working so far.
I am auditing any changes by overriding the SaveChanges method. As explained above I may, in some low cases, need to save modified entities that were disconnected. So to audit, I have to retrieve the current values from the database and then compare to work out what was changed while disconnected. If the entity has been tracked, there is no need to get the old values, as I've got access to them via the state manager. I'm not using self tracking entities, as this is overkill for my requirements.
QUESTION: In my auditing method I simply want to know if the modified entity is tracked or not, i.e. do I need to go to the db and get the original values?
Cheers
DbContext.ChangeTracker.Entries (http://msdn.microsoft.com/en-us/library/gg679172(v=vs.103).aspx) returns DbEntityEntry objects for all tracked entities. DbEntityEntry has Entity property that you could use to find out whether the entity is tracked. Something like
var isTracked = ctx.ChangeTracker.Entries().Any(e => Object.ReferenceEquals(e.Entity, myEntity));

how can i know when a self-tracking entity has been changed?

I have been working with the Entity Framework + Self-Tracking entities, and came out with a problem:
Is there any way to determine when an entity has been changed??
For example: If you have an entity User with two fields: Name and Password, you can know if an User instance has been changed making:
<user>.ChangeTracker.State != ObjectState.Unchanged;
My problem is when the User has a Person, and the person has a field Email. I want that if the email field is changed, then the corresponding User is changed too.
I have been trying with methods such as: <user>.StartTrackingAll(); but this does not work with navigation properties (or maybe i am doing something wrong). Some help about this can be found here.
Remember that the Self tracking entities are autogenerated via T4 templates, so the clases can't be modified.
First when wanting to know if any entity in a so-called object graph has changed you can recurse through all entities contained in trackable collections or one-to-one navigation properties of a root entity (user in your case). This way you can know if a person inside the root entity has changed. This is actually how I check complex object graphs for any changes in any of the contained entities. But also for checking out if any of these entities have critical validation errors (so the user can't persist them yet).
Remember that the Self tracking entities are autogenerated via T4 templates, so the clases can't be modified.
Not true. First of all you can modify the T4 template to generate more (complex) code to achieve the things you want. And second, it generates partial classes which can easily be extended with custom (non-generated) code.
If you change the email in the Person instance only that instance is correctly marked as modified. That is absolutely correct behaviour. What do you expect? Do you expect that change to property in related entity will propagate changed state to relations? That would make STEs completely useless because any single change to entity graph would make all entities in the graph modified and each this modification causes additional roundtrip to the database.
If you want to set User as modified when you are changing email simply create some method or handle some event and call person.User.MarkAsModified()

Entity Framework Service Layer Update POCO

I am using the Service Layer --> Repository --> Entity Framework (Code-First) w/POCO objects approach, and I am having a hard time with updating entities.
I am using AutoMapper to map my Domain Objects to my View Models and that works good for getting the data, no how do I get that changes back into the database?
Using pure POCO objects, I would assume that there is no sort of change tracking, so I see my only option is to handle it myself. Do you just make sure that your View Models have the EXACT same properties as your Domain Objects? What if I just change a field or two on the View Model? Won't the rest of the fields on the Domain Object get overwritten in the database with default values?
With that said, what is the best approach?
Thanks!
Edit
So what I am stumbling on is this, lets take for example a simple Customer:
1) The Controller has a service, CustomerService, that calls the services GetCustmoerByID method.
2) The Service calls into the CustomerRepository and retrieves the Customer object.
3) Controller uses AutoMapper to map the Customer to the ViewModel.
4) Controller hands the model to the View. Everything is great!
Now in the view you do some modifications of the customer and post it back to the controller to persist the changes to the database.
I would assume at this point the object is detached. So should the model have the EXACT same properties as the Customer object? And do you have to make hidden fields for each item that you do not want to show, so they can persist back?
How do you handle saving the object back to the database? What happens if your view/model only deals with a couple of the fields on the object?
If you're using EF Code First, i.e: the DbContext API, then you still do have change tracking which is taken care of by your context class.
after making changes to your objects, all you have to do is call SaveChanges() on your context and that will persist the changes to your database.
EDIT:
Since you are creating a "copy" of the entity using AutoMapper, then it's no longer attached to your context.
I guess what you could do is something similar to what you would in ASP.NET MVC (with UpdateModel). You can get the original entity from your context, take your ViewModel (which may contain changed properties) and update the old entity, either manually (just modified properties), or using AutoMapper. And then persist the changes using context.SaveChanges().
Another solution would be to send the model entity as [part of] the ViewModel. This way, you'll have your entity attached to the container and change tracking will still work.
Hope this helps :)
You are absolutely right that with a detached object you are responsible for informing the context about changes in your detached entity.
The basic approach is just set the entity as modified. This works for scalar and complex properties but it doesn't work for navigation properties (except FK relations) - for further reading about problems with navigation properties check this answer (it is related to EFv4 and ObjectContext API but same problems are with DbContext API). The disadvantage of this approach is that all fields in DB will be modified. If you just want to modify single field you still have to correctly fill others or your database record will be corrupted.
There is a way to explicitly define which fields have changed. You will set the modified state per property instead of whole entity. It is little bit harder to solve this on generic approach but I tried to show some way for EFv4 and for EFv4.1.
I agree with #AbdouMoumen that it's much simpler to use the model entities at the view level. The service layer should provide an API to persist those entities in the data store (db). The service layer shouldn't dumbly duplicate the repository lawyer (ie: Save(entity) for every entity) but rather provide a high level save for an aggregate of entities. For instance, you could have a Save(order) in the service layer which results in updating more basic entities like inventory, customer, account.

RIA services presentation model with 1-many or many-many relationships

I'm trying to get a presentation model (discussed here and here) working in RIA. All the examples I can find are simple, flat data entities with no 1-many or many-many relationships, which are what I can't get working - specifically, on updates and inserts into associative relationships.
Queries I can get working fine - I have my presentation classes marked up with Association attributes (and Include attributes, where appropriate), and I have a good understanding about how data is loaded into the client side and maintained there as entities. I also have inserts of new entities covered. However, I'm experiencing the following problems. For the following examples, assume we have simple Album and Artist entities, where an Album has a single artist and an Artist can have zero to many albums. Both have a Name property.
On the client side, if I do myArtist.Albums.Add(anAlbum) or myArtist.Albums.Remove(anAlbum), nothing happens. HasChanges returns false. (Note that myArtist and anAlbum were obtained solely in code by loading the entities and iterating to get references to specific entities: I'm not doing anything in UI or with DomainDataSources yet, just dinking around).
If I update the Name on an Artist and SubmitChanges, when the Update method gets called on the server, the Albums collection is null.
Does anyone have any suggestions, or can you point me to an example that uses more complex objects?
EDIT (keeping the above for posterity): Alright, it appears that the second issue (a reference to an entity or a collection of entities showing as null when Update gets called on the server) exists because the child entites aren't marked as Changed and so they aren't being serialized and sent back. I know you can force that to happen by using [Composition] and I have gotten it to work that way, but this is not a compositional relationship and I want both entities to be "top-level" entities. How can I mark an entity as changed?
The problem was that my [Association] attributes weren't correctly defined. I didn't realize that the association's Name property has to be the same on both sides of the association. When the names are the same and you do a build, the generated code on the client uses a different constructor for the EntityCollection used by the "parent" to refer to the "children" than it does if the associations aren't set up right. The new constructor takes callbacks that do a little bit of extra handling when you call Add and Remove on the collection - specifically, they take the child entity you are adding or removing and modify the property on it that refers to its parent so that everything remains in sync: the collection you removed the object from, the collection you added it to, and the object's reference to its parent.

Inheritance problems with Entity Framework (table per type)

For part of the project I'm currently working on, I have a set of four tables for syndicatable actions. One table is the abstract base for the other three, and each table is represented in my EF model like so:
EF Model -- Actions http://chris.charabaruk.com/system/files/images/EF+Model+Actions.png
There are two problems that I'm currently facing with this, however. The first problem is that Actor (a reference to a User) and Subject (a reference to an entity of the class associated with each type of action) are null in my subclasses, despite the associated database columns holding valid keys to rows in their associated tables. While I can get the keys via ActorReference and SubjectReference this of course requires setting up a new EF context and querying it for the referenced objects (as FooReference.Value is also null).
The second problem is that the reciprocal end of the relationship between the concrete action classes and their related entity classes always turn up nothing. For example, Task.RelatedActions, which should give me all TaskAction objects where Subject refers to the particular task object on which RelatedActions is called, is entirely devoid of objects. Again, valid rows exist in the database, Entity Framework just isn't putting them in objects and handing them to me.
Anyone know what it is I'm doing wrong, and what I should do to make it work?
Update: Seems that none of the relationship properties are working in my entity model any more, at all. WTF...
I think the issue you are experiencing here is that by default the EF does not automatically load related entities. If you load an entity, the collection or reference to related entities will be empty unless you do one of the following things:
1) Use eager loading in order to retrieve your main entity and your related entity in a single query. To do this, modify your query by adding a call to the Include method. In your sample above, you might use the following query:
from a in context.Actions.Include("Actor") select a
This would retrieve each of the actions with the related Actor method.
2) Use explicit lazy loading to retrieve the related entity when you need it:
action1.ActorReference.Load()
In the version of the EF which will ship with .Net 4.0, you will also have the following additional option:
3) Turn on implicit lazy loading so that related entities will automatically be retrieved when you reference the navigation property.
Danny