使用实体框架时,将域和数据层分开的正确方法是什么?
我下面的示例显然是错误的,因为数据层在应用IsRelevant逻辑之前正在从存储库中获取并转换所有ThingEntities。
但是,我看不到如何在不将域逻辑放入数据层的情况下获取存储库来过滤ThingEntities。
这里正确的方法是什么?谢谢。
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();
}
}
}
}
最佳答案
我不知道有没有正确的方法-但是从您的示例中确实可以改变一些事情。
域层应该知道数据层,反之亦然。这意味着您的映射器应该在域层中。另外,我将使数据层尽可能小,并摆脱存储库-我看不出将存储库与EF一起使用的意义。
尽管大多数人似乎都这样做,但我不会将保持状态的对象与业务逻辑混合在一起。换句话说,IsRelevent()
不应位于Thing
中。
考虑将ThingManager
重命名为更具体的名称,以避免违反关注点分离。我将名称留在示例中,因为我不知道它会做什么,因此不知道该叫什么。
只要返回IQueryable
,您就可以将查询分为单独的内部方法,然后将您的公共方法将它们全部组合在一起。这样,您可以重用诸如IsRelevent()
之类的查询,但只能公开公开更多更高级别的业务特定查询。
因此,您的数据层将类似于
namespace DataLayer
{
public class EfDbContext : DbContext
{
public virtual IDbSet<ThingEntity> ThingEntities { get; set; }
}
public class ThingEntity
{
public int Id { get; set; }
}
}
和你的领域层
namespace DomainLayer
{
public class Thing
{
public int Id;
}
internal class ThingEntityMapper
{
public static Thing Transform(ThingEntity thingEntity)
{
return new Thing{ Id = thingEntity.Id };
}
}
internal interface IThingQueries
{
IQueryable<ThingEntity> FilterRelevent(IQueryable<ThingEntity> things);
}
internal class ThingQueries : IThingQueries
{
public IQueryable<ThingEntity> FilterRelevent(IQueryable<ThingEntity> things)
{
return things.Where(x => x.Id%2 == 0);
}
}
public class ThingManager
{
private readonly DbContext _context;
private readonly IThingQueries _queries;
public ThingManager(DbContext _context, IThingQueries queries)
{
_context = context;
_queries = queries;
}
public List<Thing> RelevantThings()
{
return _queries
.FilterRelevent(_context.ThingEntities)
.Select(ThingEntityMapper.Transform)
.ToList();
}
}
}
这可能包含使它停止构建的错误,因为它只是用来指示通用体系结构,在该体系结构中,数据层仅用于保留实体和上下文,而域层则负责其余部分。