Entity Framework/Sql2008 - How to Automatically Update Lastmodified Fields for Entities

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

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.

Auto manage and protect Created\Updated fields with Entity Framework 5

Overwrite the 'DbContext' class or embed this in the '.tt' file (Codefirst \ DBFirst)

The code assume so you have the fields 'CreatedOn'\'ModifiedOn' inside the POCO.

If you don't have them, or you have only one - the code will work fine.

Be aware! If you use a extension (as this one) so allow you to do batch updates or changes from a stored procedure - this will not work

EDIT:

I found the source of my inspiration - thanks 'Nick' here

public override int SaveChanges()
{
var context = ((IObjectContextAdapter)this).ObjectContext;
var currentTime = DateTime.Now;
var objectStateEntries = from v in context.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified)
where v.IsRelationship == false && v.Entity != null
select v;

foreach (var entry in objectStateEntries)
{
var createdOnProp = entry.Entity.GetType().GetProperty("CreatedOn");
if (createdOnProp != null)
{
if (entry.State == EntityState.Added)
{
if (createdOnProp != null)
{
createdOnProp.SetValue(entry.Entity, currentTime);
}
}
else
{
Entry(entry.Entity).Property("CreatedOn").IsModified = false;
}
}

var modifiedOnProp = entry.Entity.GetType().GetProperty("ModifiedOn");
if (modifiedOnProp != null)
{
modifiedOnProp.SetValue(entry.Entity, currentTime);
}
}

return base.SaveChanges();
}

Is there a way to automatically set the CreatedDate/LastModifiedDate column in EF?

If you have CreatedDate and LastModifiedDate in every table, then probably you have some abstract BaseModel which has these two properties. Then you can override SaveChanges method inside your context and set these properties:

private void SetOperationDates()
{
// Get added entries
IEnumerable<ObjectStateEntry> addedEntryCollection = Context
.ObjectContext
.ObjectStateManager
.GetObjectStateEntries(EntityState.Added)
.Where(m => m != null && m.Entity != null);

// Get modified entries
IEnumerable<ObjectStateEntry> modifiedEntryCollection = Context
.ObjectContext
.ObjectStateManager
.GetObjectStateEntries(EntityState.Modified)
.Where(m => m != null && m.Entity != null);

// Set CreatedDate of added entries
foreach (ObjectStateEntry entry in addedEntryCollection)
{
BaseModel addedEntity = entry.Entity as BaseModel;
if (addedEntity != null)
addedEntity.CreatedDate = DateTime.Now;
}

// Set LastModifiedDate of modified entries
foreach (ObjectStateEntry entry in modifiedEntryCollection)
{
BaseModel modifiedEntity = entry.Entity as BaseModel;
if (modifiedEntity != null)
modifiedEntity.LastModifiedDate = DateTime.Now;
}
}

public override int SaveChanges()
{
SetOperationDates();

return SaveChanges();
}

Note: You can also add overload version of SaveChanges method whith bool parameter in case you do not want to call SetOperationDates.

Last Modified properties when using Entity Framework Extensions bulk methods

Since you use BulkMerge, why not simply creating an extension method that will set audit field first?

context.SetAuditField(list)
context.BulkMerge(list)

You can also set some global event. That's perhaps more what you are looking for

EntityFrameworkManager.PreBulkMerge = (context, entities) =>
{
// ...code...
};

How to automatically set DateCreated and DateUpdated

You can override the SaveChanges() method on your DbContext to update the DateUpdated value on Save(). I would implement an interface to allow for some items to be updated and others not.

public interface IEntityAutoDateFields
{
DateTime DateCreated { get; set; }
DateTime DateUpdated { get; set; }
}

And then:

public class PocoWithDates : IEntityAutoDateFields
{
public PocoWithDates()
{

}

public DateTime DateCreated { get; set; }
public DateTime DateUpdated { get; set; }
}

And in your context:

public PocoWithDatesContext : DbContext
{
public DbSet<PocoWithDates> PocoWithDatesSet { get; set;}

public override int SaveChanges()
{
var now = DateTime.Now;

this.ChangeTracker.DetectChanges();
foreach (var item in this.ChangeTracker.Entries()
.Where(i => i.State == EntityState.Added || i.State == EntityState.Modified)
.Where(i => i as IEntityAutoDateFields != null))
{
if (item.State == EntityState.Added)
{
(item as IEntityAutoDateFields).DateCreated = now;
}
(item as IEntityAutoDateFields).DateUpdated = now;
}
// Call the SaveChanges method on the context;
return base.SaveChanges();
}
}

Updating your edmx to reflect changes made in your db (.net linq-to-entities)

Choosing the Update Model from Database is the best method for updating your EDMX. There are certain properties that don't get updated on the Conceptual layer.

Ensure that your Store layer has been updated by viewing it in the Model Viewer toolbox. If the Store has properly been updated then you're okay, and your database is in sync. If so, go into the visual designer, click the field, go to properties, and update the NotNull property on the Conceptual side.

Logging every data change with Entity Framework

How about handling Context.SavingChanges?



Related Topics



Leave a reply



Submit