Database first , How to implement inheritance in EF6

entity-framework entity-framework-6 inheritance

Question

I'm trying to implement inheritance using entity framework 6.0 and database first approach. The reason I want to implement inheritance is because I want to add these below fields in all of my tables.

They are :(Actually in the common database design, We always add these audit field. )

  • CreatedBy
  • CreatedTime
  • ModyfiedBy
  • ModyfiedTime

I knew TPT (table-per-type) is one of the ways to make it. But I don't think TPT is the right way to solve my problem. Because TPT need create a table for the Base type. But in my case I think it is not necessary. Is there any way to make it ? Thanks.

1
1
8/11/2015 2:12:44 AM

Accepted Answer

I would suggest that database inheritance/TPT/TPH is not necessary for this situation. What you need is just an IAuditable interface:

public interface IAuditable
{
    string CreatedBy { get; set; }

    DateTimeOffset CreatedTime { get; set; }

    string ModifiedBy { get; set; }

    DateTimeOffset? ModifiedTime { get; set; }
}

Then you have two options:

  1. If you are sure all of your entities will be IAuditable, you can simply change the T4 template so that all auto-generated entities will implement IAuditable.

  2. If only some of your entities will be IAuditable, you can add partial classes to those auditable entities like:

    public partial class Foo
    {
        // Auto-generated properties by EF
        public int Id { get; set; }
        ...
    } 
    

    Then in another file:

    public partial class Foo : IAuditable
    {
        // No implementation because auditable fields already exists
    }
    

You can then derive an abstract class from DbContext to automatically update these IAuditable properties:

public abstract class AuditableDbContext : DbContext
{
    public override int SaveChanges()
    {
        UpdateAuditableProperties();
        return base.SaveChanges();
    }

    public override async Task<int> SaveChangesAsync()
    {
        UpdateAuditableProperties();
        return await base.SaveChangesAsync();
    }

    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken)
    {
        UpdateAuditableProperties();
        return await base.SaveChangesAsync(cancellationToken);
    }

    protected virtual void UpdateAuditableProperties()
    {
        var now = DateTimeOffset.Now;
        var userName = GetUserName();
        var changedAuditableEntities = from entry in ChangeTracker.Entries<IAuditable>()
                                       let state = entry.State
                                       where
                                           state.HasFlag(EntityState.Added) ||
                                           state.HasFlag(EntityState.Modified)
                                       select entry;

        foreach (var auditable in changedAuditableEntities)
        {
            var entity = auditable.Entry;

            switch (auditable.State)
            {
                case EntityState.Added:
                    entity.CreatedDate = now;
                    entity.CreatedBy = userName;
                    break;
                case EntityState.Modified:
                    entity.ModifiedDate = now;
                    entity.ModifiedBy = userName;
                    break;
            }
        }
    }

    protected abstract string GetUserName();
}

Your DbContext can derive from AuditableDbContext and then implement GetUserName() to supply the username who creates/modifies the entities.

7
6/28/2018 5:52:28 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow