Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way to separate data and domain layers with Entity Framework

What is the correct way to separate the domain and data layers when using Entity Framework?

My example below is clearly wrong because the data layer is fetching and transforming ALL ThingEntities from the repository before applying the IsRelevant logic.

However, I can't see how to get the repository to filter the ThingEntities without putting domain logic into the data layer.

What's the correct approach here? Thanks.

namespace DomainLayer
{
    public class Thing
    {
        public int Id;
        public Thing(int id) { Id = id; }
        public bool IsRelevant()
        {
            return Id%2 == 0;  // or some domain-specific logic
        }
    }

    public interface IThingRepo
    {
        List<Thing> Things { get; }
    }

    public class ThingManager
    {
        private readonly IThingRepo _thingRepo;
        public ThingManager(IThingRepo thingRepo)
        {
            _thingRepo = thingRepo;
        }
        public List<Thing> RelevantThings()
        {
            return _thingRepo.Things.Where(x => x.IsRelevant()).ToList();
        } 
    }
}

namespace DataLayer
{
    public class EfDbContext : DbContext
    {
        public virtual IDbSet<ThingEntity> ThingEntities { get; set; }
    }

    public class ThingEntity
    {
        public int Id { get; set; }
    }

    public class ThingEntityMapper
    {
        public static Thing Transform(ThingEntity thingEntity)
        {
            return new Thing(thingEntity.Id);
        }
    }

    public class ThingRepo : IThingRepo
    {
        private readonly EfDbContext _context;
        public ThingRepo(EfDbContext context)
        {
            _context = context;
        }
        public List<Thing> Things
        {
            get
            {
                var result = Enumerable.Empty<Thing>();
                foreach (var thingEntity in _context.ThingEntities)
                {
                    result = result.Concat(new[] {ThingEntityMapper.Transform(thingEntity)});
                }
                return result.ToList();
            }
        }
    }
}
like image 750
SJC Avatar asked Dec 07 '25 07:12

SJC


1 Answers

Entity Framework pretty much can be seen as a public API over the marriage and simplification of the domain and data access layers, so if you want a distinct separation you generally end up writing superfluous code to encapsulate everything behind a repository or domain layer (which is quickly falling out of fashion).

My suggestion is to make your peace with what appears to be a violation of separation of concerns and take advantage of calling the context directly from your business logic at first. Then if you see a reason to abstract it behind a separate layer, let that happen organically instead of defining a line of demarcation between your layers from the beginning. You'll save yourself a lot of time agonizing over whether or not "the rules" are being followed.

I prefer to think of it this way: If I had engineered EF from the beginning, would I have as much problem with consuming the context in my code? Probably not, because I'd view the code I'd written as creating a layer between the DAL and my higher-level logic.

Overall, my opinion is that the general source of discomfort for devs comes from not being in charge of designing the code that the context and table abstractions provide. If you were, you might view the problem differently.

like image 197
moarboilerplate Avatar answered Dec 08 '25 20:12

moarboilerplate