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. )
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.
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:
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
.
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.