3k-pwg
Last Updated: July 24, 2017
·
3.14K
· teyc
Bd6e62afb4881ab0f617611b8b65d003

Dynamic Data, Entity Framework and Modified Date

It is a pretty common requirement that some business logic is executed when an entity has been updated. The standard way to do this is to override SaveChanges() on your DbContext.

Unfortunately, this does not work with ASP.net Dynamic Data. Dynamic Data works with the DbContext's underlying ObjectContext.

Fortunately for us, the ObjectContext raises an event just before changes are saved. So the solution is straightforward: we need to hook the ObjectContext's SavingChanges event and call our custom code.

using System;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;

public class MyDbContext : System.Data.Entity.DbContext
{
    public DbContext() : base() { HookSaveChanges(); }

    public DbSet<ShoppingCart> ShoppingCarts{ get; set; }
    public DbSet<Product> Products { get; set; }

    /* Custom SaveChanges to execute business logic */
    public override int SaveChanges()
    {
        OnSavingChanges();
        return base.SaveChanges();
    }

    /* Dynamic Data does not call DbContext.SaveChanges.
     *  this hooks the underlying ObjectContext
     */
    private void HookSaveChanges()
    {
        (this as IObjectContextAdapter).ObjectContext.SavingChanges += (sender, e) =>
        {
            OnSavingChanges();
        };
    }

    private void OnSavingChanges()
    {
        this.ChangeTracker.DetectChanges();
        foreach (var item in this.ChangeTracker.Entries())
        {
            ITimeStampedEntity ts = item.Entity as ITimeStampedEntity;
            if (ts != null)
            {
                if (item.State == EntityState.Added)
                {
                    ts.DateCreated = DateTime.Now;
                    ts.DateModified = ts.DateCreated;
                }
                else if (item.State == EntityState.Modified)
                {
                    ts.DateModified = DateTime.Now;
                }
            }
        }
    }
}

internal interface ITimeStampedEntity
{
    DateTime DateCreated { get; set; }
    DateTime DateModified { get; set; }
}
Say Thanks
Respond

5 Responses
Add your response

6474

I have used your logic as you provided, there is two issue
1. The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range value.

but the above error comes only while State = Modified ( State = Added is fine ).

I could able to fix this error by physically changing datetime into datetime2 in table definition.

Second Issue ( not resolved)
While updating the record it update the modified date correctly and update "DateCreated" also with initial value ( ' 01-Jan-01 12:00:00 AM ) ... How to resolve the above issue

over 1 year ago ·
6482

Following code resolved my second issue

if (item.State == EntityState.Modified)
{
DateTime a = item.GetDatabaseValues().GetValue<DateTime>("DateCreated");
int b = item.GetDatabaseValues().GetValue<int>("CreatorId");
ts.DateCreated = a;
ts.DateModified = DateTime.Now;
ts.CreatorId = b;
ts.UpdaterId = userId;
}

over 1 year ago ·
9817

Thank you! I did not know about events before. This is magical!

over 1 year ago ·
15092
55c86ad6e1403b266c35e859e143c50c

fortunately indeed! thanks.

over 1 year ago ·
29123

I tried above code but it is not working.
ITimeStampedEntity ts = item.Entity as ITimeStampedEntity;
I'm getting null at this line. what could be the reason?
Help me out.

5 months ago ·