1

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
  • Please tell my why downvote my question . Thanks. Commented Aug 11, 2015 at 2:00

1 Answer 1

7

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.

Sign up to request clarification or add additional context in comments.

6 Comments

:) yeah . Right . I just search something similar in the google. (EF + audit fileds) . your answer help me lot . Thanks. +++1
Could you please share some code of how to insert or update an entity ? especially for these audit fields. Thanks.
wow.. Very nice . But , Have you ever think of how to make it in the edmx designer ? I mean maybe it need to change the generated code of entity inherit from the IAuditable when the edmx updated. Is there any possibility to do that ? Thanks.
As I mentioned in my first option, you can change the T4 template which generates the entities. Normally it has an extension of .tt which resides next to your .edmx file
yeah .. That should be the way to make it . I just test it in the entity framework 6. .tt file is the code generation template file. That is it works for. :) Thanks.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.