简体   繁体   中英

Using Entity Framework 6 attributes, store row creation date and last updated date

I am creating models using Entity Framework 6.1.3 and I would like to store the UTC date and time of when a row is created and when it was last updated.

I have the following model (simplified):

namespace Sapphire.Cms.Models {
    using System;
    using System.ComponentModel.DataAnnotations;

    public class SiteTree {
        [Required]
        [DataType(DataType.DateTime)]
        [Display(Name = "Created")]
        public DateTime Created { get; set; }

        [Required]
        [DataType(DataType.DateTime)]
        [Display(Name = "Last Updated")]
        public DateTime LastUpdated { get; set; }
    }
}

For the Created field, I would like to store the UTC date and time of when the row was created in a datetime field named Created in MSSQL.

For the LastUpdated field, I would like to store the UTC date and time of when the row was last updated in a datetime field named LastUpdated in MSSQL every time the row is updated.

I would like the ability to use attributes so that I can indicate when this data should automatically be populated.

For instance, for the LastUpdated property:

    [Required]
    [DataType(DataType.DateTime)]
    [Display(Name = "Last Updated")]
    [TrackLastUpdated]
    public DateTime LastUpdated { get; set; }

I want the ability to use these attributes for other models too.

The timezone on the server changes from GMT to BST and back, so storing this value in UTC and getting the value out in UTC is vitally important.

There are similar questions on SO, but none using attributes from what I can see:

I'm hoping that EF already has some attributes to do this however I can't seem to find them. If not can someone please explain how I can achieve this?

Okay, take a look at this. This is what I'm using here. First, create this interface and decorate your classes with it that you want to audit.

public interface IAuditableEntity
{
    DateTime CreatedDateUtc { get; set; }
    DateTime ModifiedDateUtc { get; set; }

    string CreatedBy { get; set; }
    string ModifiedBy { get; set; }
}

Your data context constructor needs to wire up for the ObjectContext 's saving event. Please ignore the clock bit, it's not necessary.

public MyContext()
    : this(null, "Name=MyContext")
{
}

public MyContext(IClock clock, string connectionString)
    : base(connectionString)
{
    _clock = clock;

    var objCtx = ((IObjectContextAdapter) this).ObjectContext;
    objCtx.ObjectMaterialized += ObjectMaterialized;
    objCtx.SavingChanges += ObjectContext_SavingChanges;
}

Here is the handler, and where the magic happens. It gets all the new and modified entities and sets the fields as appropriate before saving:

private static void ObjectContext_SavingChanges(object sender, EventArgs e)
{
    var objCtx = sender as ObjectContext;
    if (objCtx == null)
        return;

    var username = Thread.CurrentPrincipal != null ? Thread.CurrentPrincipal.Identity.Name : String.Empty;
    var auditableEntries =
        (from entry in objCtx.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified)
            where !entry.IsRelationship
            let entity = entry.Entity as IAuditableEntity
            where entity != null
            select new
            {
                entity,
                entry.State
            }).ToList();

    foreach (var entry in auditableEntries.Where(x => x.State == EntityState.Added))
    {
        entry.entity.CreatedDateUtc = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc);
        entry.entity.CreatedBy = username;
    }

    foreach (var entry in auditableEntries.Where(x => x.State == EntityState.Modified))
    {
        entry.entity.ModifiedDateUtc = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc);
        entry.entity.ModifiedBy = username;
    }
}

Note that I haven't tested this code fully. It might have a bug. You could possibly do this with a Convention and a custom attribute, but I'm not so sure.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM