Search code examples
c#entity-frameworkinterfaceentity-framework-coreinterface-segregation-principle

Cast EF6 and EFCore Entity to a single Interface?


Is it possible to join different version of Entity Framework (Core) Entities from two applications based on EF 6 (with .NetFramework 4.0) and EF Core 5.0 (.Net Standard 2.1) with the same DataBase into one Entity Interface instead of using the actual database classes that both entity frameworks provide, using a project that contains Interfaces of the actual DataBase Entities and targets both EF 6 and EF Core 5 supported framework platforms?

<!--EntityTypes.csproj-->
...
<TargetFrameworks>netstandard2.1; net40; net45</TargetFrameworks>
....
// IEntity.cs
namespace EntityTypes
{
    public interface IEntity
    {
        long EntityID { get; set; }
        string EntityName { get; set; }
    }
}

In both .Net Core and Framework 4.0 projects, I need to somehow use syntax like

var _entitiesContext = new EntitiesContext(); 
public static List<IEntity> BuildSet<T>() where T : class
{
    return _entitiesContext.Entities.ToList().Cast<IEntity>().ToList();
}

As I've already found in this question : How to Cast DBSet to Interface in Anonymous Method - E.F But without getting into the Runtime Error

System.InvalidCastException: 'Unable to cast object of type 
'System.Data.Entity.DynamicProxies.Entity_33C84C30E063218CBB4881E395838375014F3EFBA09108F25ACF2FB2FCA1E92D' 
to type 'EntityTypes.IEntity'.'

Solution

  • a project that contains Interfaces of the actual DataBase Entities and targets both EF 6 and EF Core 5 supported framework platforms?

    Basically, this is simple. You don't need any entity interfaces. Just define your entities in a separate assembly that you reference from both EF projects, and create an abstract class or interface that defines the repository that you can implement with either an EF Core or EF6 DbContext, eg:

    public class SomeEntity
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    public class AnotherEntity
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    public abstract class Repository : IDisposable
    {
        public abstract IQueryable<SomeEntity> SomeEntities { get; }
        public abstract IQueryable<AnotherEntity> AnotherEntities { get; }
    
        public abstract void SaveChanges();
        public abstract void Dispose();
    
    }
    

    You'll have to add methods to get shaped data because eager loading with Include is a version-specific extension, or provide methods to pass expressions into your abstract repository and create the Include in the version-specific subclass. But basic queries with IQueryable will work fine.