Mas*_*oud 21 c# entity-framework repository viewmodel ef-code-first
我使用领域驱动n层应用程序体系结构与EF code first我在最近的项目中,我定义我的Repository合同,在Domain层.制定其他Repositories不那么冗长的基本合同:
public interface IRepository<TEntity, in TKey> where TEntity : class
{
TEntity GetById(TKey id);
void Create(TEntity entity);
void Update(TEntity entity);
void Delete(TEntity entity);
}
Run Code Online (Sandbox Code Playgroud)
并且Repositories每个都是专门的Aggregation root,例如:
public interface IOrderRepository : IRepository<Order, int>
{
IEnumerable<Order> FindAllOrders();
IEnumerable<Order> Find(string text);
//other methods that return Order aggregation root
}
Run Code Online (Sandbox Code Playgroud)
如您所见,所有这些方法都依赖于Domain entities.但在某些情况下,应用程序UI需要一些不是Entity数据的数据,这些数据可能来自两个或更多的肠炎数据View-Model,在这些情况下,我定义了View-Models in Application layer,因为它们非常依赖于Application's需求而不是到了Domain.
所以,我觉得我有2个办法是将数据显示为View-Models在UI:
Repository依赖Entities,并将Repositories方法的结果映射到View-Models我想向用户显示的时间(Application Layer通常).Repositories返回结果的方法View-Models,然后使用这些返回的值,Application Layer然后UI(这些Repositories我称之为Readonly Repository Contracts的特殊合同,Application Layer与其他Repositories放入的合同不同Domain).

假设,我UI需要一个View-Model3或4个属性(从3或4 大 Entities).它的数据可以通过简单的投影生成,但是在情况1中,因为我的方法无法访问View-Models,我必须使用有时的巨大连接来获取所有3或4个表的所有字段,然后将结果映射到View-Models.但是,在情况2中,我可以简单地使用投影并View-Model直接填充s.
因此,我认为从性能的角度来看,案例2优于案例1.但我认为Repository应该依赖于Entities而不是View-Models设计观点.
有没有更好的方法不会导致DomainLayer依赖于Application layer,而且还没有达到性能?还是可以接受的阅读查询,我的Repositories依靠View-Models?(情形2)
tur*_*ula 21
也许使用命令查询分离(在应用程序级别)可能会有所帮助.
您应该使您的存储库仅依赖于实体,并且只保留存储库中的普通检索方法(即GetOrderById())(当然还有create/update/merge/delete).想象一下,实体,存储库,域服务,用户界面命令,处理这些命令的应用程序服务(例如,处理Web应用程序中的POST请求的某个Web控制器等)代表您的写入模型,你的申请的写作方.
然后构建一个单独的读取模型,可以像你想要的那样脏 - 把5个表的连接放在那里,从文件中读取宇宙中恒星数量的代码,将它与以A开头的书籍数量相乘(之后)对Amazon进行查询并建立一个n维结构等等 - 你明白了:)但是,在阅读模型上,不要添加任何处理修改实体的代码.您可以从此读取模型中自由返回所需的任何视图模型,但可以从此处触发任何数据更改.
该分离读取和写入应适当减少程序的复杂性,让一切有点更易于管理.而且您可能也会发现它不会破坏您在问题中提到的设计规则(希望如此).
从性能的角度来看,使用读取模型,即编写与编写/更改数据的代码分开读取数据的代码是尽可能最好的:)这是因为你甚至可以在那里修改一些SQL代码没有在晚上睡不着觉 - 如果写得好,SQL查询将为您的应用程序提供相当大的速度提升.
Nota bene:我开玩笑说你可以用什么以及如何编写读取端 - 读取端代码应该像写入端代码一样干净简单,当然:)
此外,如果需要,您可以摆脱通用存储库接口,因为它只会使您正在建模的域变得混乱,并强制每个具体的存储库公开不必要的方法:)请参阅此.例如,很可能Delete()方法永远不会用于OrderRepository - 因为,或许永远不应该删除Orders(当然,一如既往,它取决于).当然,您可以将数据库行管理原语保存在单个模块中,并在具体存储库中重用这些原语,但不要将这些原语暴露给除了存储库的实现之外的任何其他原语 - 只是因为它们在其他任何地方都不需要如果公开暴露,可能会使醉酒的程序员感到困惑.
最后,也许以太严格的方式不考虑域层,应用层,数据层或视图模型层也是有益的.请阅读本文.根据实际意义/目的(或功能)打包软件模块比根据不自然,难以理解,难以解释为5个孩子的标准打包软件模块要好一些,即按层包装.