Self tracking entities. Awesome.
Except when you do something like
return Db.Users;
none of the self-tracking entities are tracking (until, possibly, they are deserialized).
Fine. So we have to recognize that there is a possibility that an entity returning to us does not have tracking enabled.
Now what???
Things I have tried
For the given method body:
using (var db = new Database())
{
if (update.ChangeTracker.ChangeTrackingEnabled)
db.C开发者_JS百科onfigurations.ApplyChanges(update);
else
FigureItOut(update, db);
db.SaveChanges();
update.AcceptChanges();
}
The following implementations of FigureItOut
all fail:
db.Configurations.Attach(update);
db.DetectChanges();
Nor
db.Configurations.Attach(update);
db.Configurations.ApplyCurrentValues(update);
Nor
db.Configurations.Attach(update);
db.Configurations.ApplyOriginalValues(update);
Nor
db.Configurations.Attach(update);
db.Configurations.ApplyChanges(update
Nor about anything else I can figure to throw at it, other than
- Getting the original entity from the database
- Comparing each property by hand
- Updating properties as needed
What, exactly, am I supposed to do with self-tracking entities that aren't tracking themselves??
Small update:
Blindly marking the entity as modified works, however this seems a bit smelly. Is it the best we can do in this case?
scenario 1
Here are some recommended practices to follow. When you are using STE in WCF scenario, you should rely on the change tracker that STE implements so on the server side you do the following.
db.Users.ApplyChanges(user);
db.SaveChanges();
scenario 2 However if you are on the server, the recommended practice is to create a method on the partial class for objectcontext called EnableChangeTracking. The method would query for entities that are in unchanged state that implements IObjectWithChangeTracker and turns on change tracking so something like this
user = db.users.first(u => u.userid == 1);
db.EnableChangeTracking();
now try to save the user entity from a different context from which it was originally retrieved from
db2.users.ApplyChanges(user);
db2.SaveChanges();
scenario 3 if on the server side you are connected to the same object context from which you retrieved the user entity from, then you use STE as simple poco object like below
user = db.users.first(u => u.userid == 1);
user.LastName = "XYZ";
db.DetectChanges(); //no need for it cuz Savechanges implicitly calls this.
db.SaveChanges();
scenario 4 if the user entity is retrieved from a different context then the context u will use it to save then here is another option where u mark the entity as modified and not care what got modified.
user = db.users.first(u => u.userid == 1);
var db2 = new ObjectContext();
user.LastName = "XYZ";
db2.Users.Attach(user);
// i prefer this option..
db2.ObjectStateManager.ChangeObjectState(user,EntityState.Modified);
db2.SaveChanges(); // updates all columns
scenario 5 if the user entity is retrieved from a different context then the context u will use it to save then here is another option where u retrieve the original entity.
user = db.users.first(u => u.userid == 1);
user.lastName ="XYZ";
var db2 = new ObjectContext();
db2.Users.First(u => u.userid == user.userid);
db2.users.ApplyCurrentValues(user);
db2.SaveChanges();
Here is a blog post that describes few scenarios. http://weblogs.asp.net/zeeshanhirani/archive/2010/03/30/modifying-self-tracking-entity-on-the-server.aspx
I extensively cover these concepts in my Entity Framework 4.0 recipes book with lots of scenarios..
精彩评论