Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework/SQL2008 - How to Automatically Update LastModified fields for Entities?

If i have the following entity:

public class PocoWithDates {    public string PocoName { get; set; }    public DateTime CreatedOn { get; set; }    public DateTime LastModified { get; set; } } 

Which corresponds to a SQL Server 2008 table with the same name/attributes...

How can i automatically:

  1. Set the CreatedOn/LastModified field for the record to now (when doing INSERT)
  2. Set the LastModified field for the record to now (when doing UPDATE)

When i say automatically, i mean i want to be able to do this:

poco.Name = "Changing the name"; repository.Save();  

Not this:

poco.Name = "Changing the name"; poco.LastModified = DateTime.Now; repository.Save(); 

Behind the scenes, "something" should automatically update the datetime fields. What is that "something"?

I'm using Entity Framework 4.0 - is there a way that EF can do that automatically for me? (a special setting in the EDMX maybe?)

From the SQL Server side, i can use DefaultValue, but that will only work for INSERT's (not UPDATE's).

Similarly, i can set a default value using a constructor on the POCO's, but again this will only work when instantiating the object.

And of course i could use Triggers, but it's not ideal.

Because i'm using Entity Framework, i can hook into the SavingChanges event and update the date fields here, but the problem is i need to become "aware" of the POCO's (at the moment, my repository is implemented with generics). I would need to do some sort of OO trickery (like make my POCO's implement an interface, and call a method on that). I'm not adversed to that, but if i have to do that, i would rather manually set the fields.

I'm basically looking for a SQL Server 2008 or Entity Framework 4.0 solution. (or a smart .NET way)

Any ideas?

EDIT

Thanks to @marc_s for his answer, but i went with a solution which is better for my scenario.

like image 356
RPM1984 Avatar asked Oct 07 '10 05:10

RPM1984


People also ask

How do I update an existing record in Entity Framework?

We can update records either in connected or disconnected scenarios. In the connected Scenario, we open the context, query for the entity, edit it, and call the SaveChanges method. In the Disconnected scenario, we already have the entity with use. Hence all we need to is to attach/add it to the context.

How does Entity Framework update data?

Update Objects in Entity Framework 4.0First retrieve an instance of the entity from the EntitySet<T> (in our case ObjectSet<Customer>), then edit the properties of the Entity and finally call SaveChanges() on the context.

How do you refresh a table in Entity Framework?

Use the Refresh method: context. Refresh(RefreshMode. StoreWins, yourEntity);


2 Answers

I know I'm a little late to the party, but I just solved this for a project I'm working on and thought I'd share my solution.

First, to make the solution more re-usable, I created a base class with the timestamp properties:

public class EntityBase {     public DateTime? CreatedDate { get; set; }     public DateTime? LastModifiedDate { get; set; } } 

Then I overrode the SaveChanges method on my DbContext:

public class MyContext : DbContext {     public override int SaveChanges()     {         ObjectContext context = ((IObjectContextAdapter)this).ObjectContext;          //Find all Entities that are Added/Modified that inherit from my EntityBase         IEnumerable<ObjectStateEntry> objectStateEntries =             from e in context.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified)             where                 e.IsRelationship == false &&                 e.Entity != null &&                 typeof(EntityBase).IsAssignableFrom(e.Entity.GetType())             select e;          var currentTime = DateTime.Now;          foreach (var entry in objectStateEntries)         {             var entityBase = entry.Entity as EntityBase;              if (entry.State == EntityState.Added)             {                 entityBase.CreatedDate = currentTime;             }              entityBase.LastModifiedDate = currentTime;         }          return base.SaveChanges();     } } 
like image 185
Nick Avatar answered Sep 19 '22 18:09

Nick


As i have a service layer mediating between my controllers (im using ASP.NET MVC), and my repository, i have decided to auto-set the fields here.

Also, my POCO's have no relationships/abstractions, they are completely independant. I would like to keep it this way, and not mark any virtual properties, or create base classes.

So i created an interface, IAutoGenerateDateFields:

public interface IAutoGenerateDateFields {    DateTime LastModified { get;set; }    DateTime CreatedOn { get;set; } } 

For any POCO's i wish to auto-generate these fields, i implement this inteface.

Using the example in my question:

public class PocoWithDates : IAutoGenerateDateFields {    public string PocoName { get; set; }    public DateTime CreatedOn { get; set; }    public DateTime LastModified { get; set; } } 

In my service layer, i now check if the concrete object implements the interface:

public void Add(SomePoco poco) {    var autoDateFieldsPoco = poco as IAutoGenerateDateFields; // returns null if it's not.     if (autoDateFieldsPoco != null) // if it implements interface    {       autoDateFieldsPoco.LastModified = DateTime.Now;       autoDateFieldsPoco.CreatedOn = DateTime.Now;    }     // ..go on about other persistence work. } 

I will probably break that code in the Add out to a helper/extension method later on.

But i think this is a decent solution for my scenario, as i dont want to use virtuals on the Save (as i'm using Unit of Work, Repository, and Pure POCO's), and don't want to use triggers.

If you have any thoughts/suggestions, let me know.

like image 35
RPM1984 Avatar answered Sep 19 '22 18:09

RPM1984