'Creating a Base Class for all entities in Entity Framework 5 in DB first approach

I have few properties like CreatedDate, ModifiedDate, VersionNo on every table. I need to change/ add values for these properties every time I modify the entity. I thought I could create a Base class with these Properties and let the Entities derive from this Base class and during SavingChanges based on ObjectState I could change the Values and Save, that way my audit entries will be isolated from the entity and the thing will be abstracted. But since I am new to Entity Framework , I am finding it difficult to understand how will I handle the mappings, etc..

If anyone can suggest ideas for implementing this, that would be really helpful. Repository code is like below:

public class GeneralRepository<T> : IRepository<T> where T : class
{
    private ObjectSet<T> _set;
    private ObjectContext _context;


    public GeneralRepository(ObjectContext context)
    {
        if (context == null) throw new ArgumentNullException("context");
        _context = context;                 // sets the context
        _set = context.CreateObjectSet<T>(); // returns the Object Set
    }


    #region Methods to override to work with ObjectGraphs .

    /// <summary>
    /// To insert data from entity into a table.
    /// </summary>
    /// <param name="entity"></param>
    public virtual void Insert(T entity)
    {
        if (entity == null) throw new ArgumentNullException("entity");
        _set.AddObject(entity);
    }


    /// <summary>
    /// To delete entity from a table. 
    /// </summary>
    /// <param name="entity"></param>
    public virtual void Delete(T entity)
    {
        if (entity == null) throw new ArgumentNullException("entity");
        _set.Attach(entity);
        _set.DeleteObject(entity);
    }


    /// <summary>
    /// To update Entity into the table
    /// </summary>
    /// <param name="entity"></param>
    public virtual void Update(T entity)
    {
        if (entity == null) throw new ArgumentNullException("entity");
        _set.Attach(entity);
        _context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
    }

    /// <summary>
    /// To get th entire table contents
    /// </summary>
    /// <returns></returns>
    public IQueryable<T> GetAll()
    {
        return _set;
    }

}



Solution 1:[1]

If you are doing database first you can always edit the T4 template to do what you want. In your Solution Explorer, expand the MyEntities.edmx file and find the MyEntities.tt file and open that up.

On line 307 you should have the following method:

public string EntityClassOpening(EntityType entity)
{
    return string.Format(
        CultureInfo.InvariantCulture,
        "{0} {1}partial class {2}{3}",
        Accessibility.ForType(entity),
        _code.SpaceAfter(_code.AbstractOption(entity)),
        _code.Escape(entity),
        _code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType)));
}

You will want to change this to:

public string EntityClassOpening(EntityType entity)
{
    return string.Format(
        CultureInfo.InvariantCulture,
        "{0} {1}partial class {2}{3}",
        Accessibility.ForType(entity),
        _code.SpaceAfter(_code.AbstractOption(entity)),
        _code.Escape(entity),
        _code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType) ?? "MyBaseClass"));
}

You can see that if there is no BaseType provided (which you can do in the GUI, but that is for having a single Entity inherit from another entity) then we want the entity to inherit from MyBaseClass.

Now when you save this it will regenerate all your entities and they will inherit from MyBaseClass now. Simple as that.

Solution 2:[2]

I think you are on the right lines, create a base class called "EntityBase" or whatever name suits your preference and add those properties.

I would then change the repository class declaration code above to be:

public class GeneralRepository<T> : IRepository<T> where T : EntityBase

You will then be able to set the common properties within the repository where required.

As far as mapping goes, I would definately look at the Entity Framework 5 Power Tools as you have mentioned you are database first, my experience however has always been mapping using the fluent API.

Also... definately look at some of the benefits that DBContext would provide you with as opposed to ObjectContext which you are currently using within your repository.

Thanks

Solution 3:[3]

For db first, i have baseentity has status and guid variables. I removed guid and status variables from simple properties. I changed tt file like below

var simpleProperties = typeMapper.GetSimpleProperties(entity);
var isBaseEntity = simpleProperties.Any(x => x.Name == "GUID") && simpleProperties.Any(x => x.Name == "STATUS");
if (simpleProperties.Any())
{
    foreach (var edmProperty in simpleProperties)
    {
    
    if(isBaseEntity && (edmProperty.Name == "GUID" || edmProperty.Name == "STATUS")){
        continue;
    }

    }
}


    public string EntityClassOpening(EntityType entity)
{
    var properties= _typeMapper.GetSimpleProperties(entity);
    var isBaseEntity = properties.Any(x => x.Name == "GUID") && properties.Any(x => x.Name == "STATUS");
    var baseEntityName = "";
    if(isBaseEntity){
        baseEntityName="BaseEntity";
    }
    
    return string.Format(
        CultureInfo.InvariantCulture,
        "{0} {1}partial class {2}{3}",
        Accessibility.ForType(entity),
        _code.SpaceAfter(_code.AbstractOption(entity)),
        _code.Escape(entity),
        _code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType)??baseEntityName));
}

Solution 4:[4]

Create a base class like BaseEntity and include the properties you want inside that class. Derive your entities from BaseEntity and define your repository like this :

public class GeneralRepository<T> : IRepository<T> where T : BaseEntity

For mapping, there are 3 variations: Table per Hierarchy, Table per Type, and Table per Concrete Type. You can find information about them in Msdn.

If you have mostly unrelated entities, I would go with Table per Concrete Type and create seperate tables for each entity, by calling ToTable("Apples") in your EntityTypeConfiguration class (Fluent API).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jeff Treuting
Solution 2 BenjaminPaul
Solution 3 Veysel Kurhan
Solution 4