How to auto-update the Modified property on a Entity in Entity Framework 4 when saving?
Im using EF4 in VS2010, POCO's and the model-first approach.
My entity has the following properties: Id:Guid, Name:String, Created:DateTime, Modified:DateTime, Revision:Int32.
I create my entity, set the name and save it to the database using the EF4-context. This should set Id to a new Guid (works with Identity-SGP), Created set to now, Modified left as null, Revision set to 0. I retrieve the entity, change the name and save it again. This time the Modified-value should be set to now and revision should be 1.
How do I best accomplish this using EF4 with the EDMX-designer?
Update:
This was what I ended up using:
public override int SaveChanges(System.Data.Objects.SaveOptions options)
{
foreach (ObjectStateEntry entry in ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified).Where(e => e.Entity is EntityBase))
{
EntityBase entity = entry.Entity as EntityBase;
if (entry.State == EntityState.Added)
{
entity.Version = new Version() { Major = 1, Minor = 0, Revision = 0 };
entity.Created = DateTime.Now;
if (OperationContext.Current != null) entity.CreatedBy = OperationContext.Current.ServiceSecurityContext.WindowsIdentity.Name;
}
else if (entry.State == EntityState.Modified)
{
entity.Version.Revision++;
entity.Modified = DateTime.Now;
if (OperationContext.Current != null) entity.ModifiedBy = OperationContext.Current.ServiceSecurityContext.WindowsIdentity.Name;
}
}
return base.SaveChanges(options);
}
Which isnt working... :(
The problem is that the entry.State is still unmodified even if I explicitly run the MarkAsModified()-method. I dont get this...
Why isnt change-tracking enabled by default? Im using self-tracking entities so why would I want it off and explicitly turn it on everytime? And why is entities persisted to db even if state is unmodified? And w开发者_JS百科hats the difference between EntityState and ObjectState? At the moment Im making all changes and updates serverside but I will also use a WCF-service to transfer entities back and forth some time later... Is there a difference in how changes are treated here? If serverside all changes, no matter changetracking on/off, is persisted?? What I want is that nothing should ever be able to be stored without also updating Modified, Revision etc. These properties should always be set on the server when the object is received back and has changed. (Im not talking sql-server-side here but service-server-side)
Let's assume your Entity Type name is Product:
partial void OnContextCreated() {
this.SavingChanges += Context_SavingChanges;
}
void Context_SavingChanges(object sender, EventArgs e) {
IEnumerable objectStateEntries =
from ose
in this.ObjectStateManager.GetObjectStateEntries(EntityState.Added |
EntityState.Modified)
where ose.Entity is Product
select ose;
Product product = objectStateEntries.Single().Entity as Product;
product.ModifiedDate = DateTime.Now;
product.ComplexProperty.Revision++;
}
If you are looking to use this code for populating common field such as ModifiedDate or ModifiedBy for all of your entities then please take a look at this post:
Entity Framework - Auditing Activity
By the way, StoreGeneratedPattern and ConcurrencyMode has nothing to do with this, they are there for completely different and unrelated stuff.
I'm partial to a client-side code-based solution, personally. Since you're using POCOs, it'd probably be simplest to have the object itself do the updating. Update the set accessor on the Name property to call an "objectModified" method that changes the Modified and Revision properties.
If that's unpalatable due to the time difference between the time the property is changed and the time the object is saved, you can tap into the partial class on your Entities object. Doing so will allow you to override the SaveChanges method where you can touch your entites in their ObjectSet<T> property on the Entities object. Something like:
public partial class YourEntities
{
public override int SaveChanges(System.Data.Objects.SaveOptions options)
{
//update your objects here
return base.SaveChanges(options);
}
}
We can use partial class and override SaveChanges method to achieve this.
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace TestDatamodel
{
public partial class DiagnosisPrescriptionManagementEntities
{
public override int SaveChanges()
{
ObjectContext context = ((IObjectContextAdapter)this).ObjectContext;
foreach (ObjectStateEntry entry in
(context.ObjectStateManager
.GetObjectStateEntries(EntityState.Added | EntityState.Modified)))
{
if (!entry.IsRelationship)
{
CurrentValueRecord entryValues = entry.CurrentValues;
if (entryValues.GetOrdinal("ModifiedBy") > 0)
{
HttpContext currentContext = HttpContext.Current;
string userId = "nazrul";
DateTime now = DateTime.Now;
if (currContext.User.Identity.IsAuthenticated)
{
if (currentContext .Session["userId"] != null)
{
userId = (string)currentContext .Session["userId"];
}
else
{
userId = UserAuthentication.GetUserId(currentContext .User.Identity.UserCode);
}
}
if (entry.State == EntityState.Modified)
{
entryValues.SetString(entryValues.GetOrdinal("ModifiedBy"), userId);
entryValues.SetDateTime(entryValues.GetOrdinal("ModifiedDate"), now);
}
if (entry.State == EntityState.Added)
{
entryValues.SetString(entryValues.GetOrdinal("CreatedBy"), userId);
entryValues.SetDateTime(entryValues.GetOrdinal("CreatedDate"), now);
}
}
}
}
return base.SaveChanges();
}
}
}
精彩评论