我正在使用 Domain driven N-layered application architecture与 EF code first
在我最近的项目中,我定义了我的 Repository
契约(Contract),在Domain
层。
制作其他基本契约(Contract)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);
}
和专业Repositories
每个Aggregation root
,例如:
public interface IOrderRepository : IRepository<Order, int>
{
IEnumerable<Order> FindAllOrders();
IEnumerable<Order> Find(string text);
//other methods that return Order aggregation root
}
如您所见,所有这些方法都依赖于 Domain entities
.
但在某些情况下,应用程序的 UI
, 需要一些不是 Entity
的数据,该数据可能由两个或多个肠炎数据(View-Model
s)组成,在这些情况下,我定义了View-Model
在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 Contract
s,放入Application Layer
不同于其他Repositories
放入Domain
的合约)。
假设,我的 UI
需要 View-Model
具有 3 或 4 个属性(来自 3 或 4 big Entities
)。
它的数据可以通过简单的投影生成,但在情况 1 中,因为我的方法无法访问 View-Models
,我必须获取所有 3 或 4 个表的所有字段,有时需要大量连接,然后将结果映射到 View-Models
.
但是,在情况 2 中,我可以简单地使用投影并填充 View-Model
直接。
所以,我认为从性能的角度来看,案例 2 比案例 1 好。但我读到 Repository
应该取决于 Entities
而不是 View-Models
从设计的角度来看。
有没有更好的方法不会导致 Domain
层取决于 Application layer
,也不影响性能?或者对于阅读查询,我的 Repositories
是否可以接受取决于 View-Models
?(案例2)
最佳答案
也许使用 command-query separation (在应用程序级别)可能会有所帮助。
您应该让您的存储库仅依赖于实体,并且只保留琐碎的检索方法 - 即 GetOrderById() - 在您的存储库中(连同创建/当然是更新/合并/删除)。想象一下,实体、存储库、领域服务、用户界面命令、处理这些命令的应用程序服务(例如,在 Web 应用程序中处理 POST 请求的某个 Web Controller 等)代表您的 write模型,您的应用程序的写入端。
然后构建一个单独的读取模型,它可以像您希望的那样脏 - 将 5 个表的连接放在那里,从文件中读取宇宙中恒星数量的代码,将其相乘以 A 开头的书籍数量(在对 Amazon 进行查询之后)并构建一个 n 维结构等等 - 你明白了 :) 但是,在读取模型上,不要添加任何处理的代码修改你的实体。您可以自由地从这个读取模型返回任何您想要的 View 模型,但请从这里触发任何数据更改。
读写分离应该会降低程序的复杂性并使一切更易于管理。您可能还会看到它不会违反您在问题中提到的设计规则(希望如此)。
从性能的角度来看,使用读取模型,即将读取数据的代码与写入/更改<的代码分开编写/strong> 数据是你能得到的最好的 :) 这是因为你甚至可以在晚上不睡不好的情况下在那里修改一些 SQL 代码——而且 SQL 查询,如果写得好,会给你的应用程序带来相当大的速度提升。
Nota bene:我开玩笑说您可以为读取端编写什么以及如何编写代码 - 当然,读取端代码应该像写入端代码一样干净和简单: )
此外,如果您愿意,您可以摆脱通用存储库接口(interface),因为它只会使您正在建模的域变得困惑,并迫使每个具体的存储库公开不必要的方法:) 请参见 this .例如,Delete() 方法很可能永远不会用于 OrderRepository - 因为,也许永远不应该删除 Orders(当然,一如既往,这取决于)。当然,您可以将 database-row-managing 原语保留在单个模块中,并在您的具体存储库中重用这些原语,但不要将这些原语公开给存储库的实现以外的任何其他人 - 仅仅是因为它们在其他任何地方都不需要,如果公开暴露可能会使醉酒的程序员感到困惑。
最后,或许不考虑领域层、应用层、数据层或 View 模型也会有好处以过于严格的方式分层。请阅读 this. 按现实世界的意义/目的(或功能)打包软件模块比基于不自然、硬-理解,hard to explain-to-a-5-old-kid 标准,即按层包装它们。
关于c# - 将 View 模型与存储库模式结合使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23287942/