I'm new to Entity Framework, in the past I've used Enterprise Library or ADO.NET directly to map models to database tables. One pattern that I've used is to put my common audit fields that appear in every table in a Base Class and then inherit that Base Class for every object.
I take two steps to protect two of the fields (Created, CreatedBy):
- Have a parameterless constructor private on the Base Enitity and create a second one that requires Created and CreatedBy are passed on creation.
- Make the setters Private so that the values cannot be changed after the object is created.
Base Class:
using System;
namespace App.Model
{
[Serializable()]
public abstract class BaseEntity
{
public bool IsActive { get; private set; }
public DateTimeOffset Created { get; private set; }
public string CreatedBy { get; private set; }
public DateTimeOffset LastUpdated { get; protected set; }
public string LastUpdatedBy { get; protected set; }
private BaseEntity() { }
protected BaseEntity(DateTimeOffset created, string createdBy)
{
IsActive = true;
Created = created;
CreatedBy = createdBy;
LastUpdated = created;
LastUpdatedBy = createdBy;
}
}
}
Inherited Class:
using System;
namespace App.Model
{
[Serializable()]
public class Person : BaseEntity
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public Person(DateTimeOffset created, string createdBy) :
base(created, createdBy) { }
}
}
I've run into issues with both. EF requires a parameterless constructor to create objects. EF will not create the database columns that have a private setter.
My question is if there is a better approach to accomplish my goals with EF:
- Require that the values for Created and CreatedBy are populated at instantiation.
- The values of Created and CreatedBy cannot be changed.
SaveChangesin your context and do all audit-related actions there (setting creation date on new entities, setting modification date on updated entities etc). It will all be done just before save. - Patryk ĆwiekIAuditiableinstead, that way you can still have entities that shouldnt be audited, and the ones that should you can implement logic specific to that interface in your SaveChanges() call like suggested in one of the answers below, if thats what you want. - Jim Wolff