Entity Framework Db-First, Implement Inheritance

Entity Framework DB-First, implement inheritance

One possible way is to use one table for each type called TPT (table-per-type), which I prefer to use. To achieve this, you define your tables like the model shown in the following picture:

table hierarchy

Note that the relationships between child and base entity are one-to-one on their pk columns, and all common fields are moved to the base table. After creating your tables, right click on the models page in your visual studio, and select Update Model from Database..., and then in the add tab, select these 3 tables to add. At first you should see this model diagram, which needs to be changed a bit:

tables added at first

Do these steps for Person and Organization separately:

  • Right click on entity and select Properties
  • In the Base Type property select Identity
  • Select and then delete the association between this entity and Identity
  • Select and then Delete the PK (ID column) of this entity (Inherits from base entity)

After these steps save your model. Now your model should look like this:

the changed model

Now compile your project and enjoy your life!

Additional resources:

Entity Framework Designer TPH Inheritance

Database first , How to implement inheritance in EF6

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.

Entity Framework Database first How to alter entities to make them derive from a base class

What you are looking for is something similar to TPH (http://msdn.microsoft.com/en-us/data/jj618292.aspx)

I don't think this will work for you however, as you have multiple existing tables.

One of the possible solutions is:

  1. Create a base class called "BaseModel" (or something like that)
  2. Add those properties as abstracts to force them to be overridden
  3. Create a method in that base class to populate those fields, or create a helper which takes BaseModel, IsDeleted,LastUpdated, LastUpdatedUser as a parameter and update the model.
  4. Extend the partial classes generated by the model.tt file and inherit from the BaseModel class.

Thanks,
Dave

EntityFramework code-first inheritance with eager include relationship on derived class

This is now supported in EF Core 2.1. Now to see if the resulting query is not too much performance-hungry.



Related Topics



Leave a reply



Submit