【发布时间】:2016-04-02 16:20:46
【问题描述】:
当涉及到具有现代 ORM 的分层应用程序时,我经常不确定应该如何创建特定类以遵守所谓的“最佳实践”,同时还要注意性能要求。
假设您在应用程序中可能有任意数量的以下类型的对象:
-
域实体 - 这些是包含业务逻辑的丰富类(对吗?),并且根据 ORM 功能,可能直接与持久性设计相关。
-
DTO - 这些是剥离业务逻辑以便将数据传递给内部和外部客户端的更简单的类。有时这些是扁平的,但并非总是如此。
-
视图模型 - 这些类似于 DTO,因为它们更简单且没有业务逻辑,但它们通常非常扁平,并且通常包含与它们所服务的 UI 相关的额外位.
我面临的挑战是,在某些情况下,将域实体或任何面向持久性的类映射到更简单的实体(如 DTO 或 ViewModel)会妨碍您进行重要的性能优化。
例如:
假设我有一些看起来像这样的域实体:
public class Event
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime EventDate { get; set; }
// These would be reference types in most ORMs
// Pretend in the setter I have logic to ensure the headliner =/= the opener
public Band Headliner { get; set; }
public Band Opener { get; set; }
}
public class Band
{
public int Id { get; set; }
public string Name { get; set; }
public Genre Genre { get; set; }
}
在现实世界中,这些可能要复杂得多,具有各种业务逻辑,可能还有一些验证调用等。
如果我公开一个公共 API,我的 DTO 可能看起来很像这个示例,没有任何业务逻辑。
如果我还有一个想要显示事件列表的 MVC Web 应用程序,我可能想要一个看起来像这样的视图模型:
public class EventViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime EventDate { get; set; }
public int HeadlinerId { get; set; }
public string HeadlinerName { get; set; }
public int OpenerId { get; set; }
public string OpenerName { get; set; }
}
通常,人们只是使用引用提取一个完整的域实体,然后使用映射实用程序来水合视图模型。
但是,假设我有数万条记录。现在 ORM 可能正在创建一个查询风暴来填充完整的引用对象(这可能比这个例子复杂得多,有自己的引用)。用不了多久,性能就会开始严重受损。
有什么问题?
我知道我不是唯一遇到这个问题的人,所以我很想知道人们如何在维护分层应用程序的同时仍然考虑到在生成多个代表的对象时保持性能的需要相同的底层域信息。
让两个Event-ish 对象代表相同的持久化数据感觉不对,但同时持久层似乎不应该知道 DTO 或视图模型,否则有什么意义争取分离?
那么你如何解决这个问题?持久性是否知道域实体的严格、详细的表示以及这些实体中数据的轻量级描述?那些轻量级的描述是 DTO 还是一些域实体 lite?
【问题讨论】:
-
你的问题是你实际上并没有做 DDD ,你正在做 db/orm 驱动的代码设计。 DDD 是关于高级设计的,它与特定的代码实现无关。很有可能您的“域”模型建模不正确,现在您认为您的应用程序很复杂/由于“DDD”而存在问题。但是很少有开发者真正在做 DDD,大多数都在做和以前一样的事情,但是使用 DDD 词,结果令人厌恶。 CQRS 是性能的答案,但首先您需要一个适当的领域模型,然后了解 CQRS 本身是一种设计原则,而不是一些代码实现。
-
为了让每个人都简单 CQRS = 将改变业务状态的模型与不改变业务状态的模型分开。而已。没有花哨的图表,没有复杂的编码配方。它只是在设计时问自己:“这个动作会改变(持久的)状态吗?或者我只需要获取一些数据,而不需要改变任何东西”
-
@MikeSW,完全同意我不清楚 DDD / 实施断开连接。问题是我在现实世界的场景中没有看到太多解释它的地方,在那里你有有形的 UI 或 API 输出。客户/订单/项目的 DDD 示例数不胜数,但很少有 应用程序 示例在持久性、查询/报告和 UI 的上下文中显示它。所以我最后说,“这似乎与 X 教条不符……这很糟糕吗??”那么...知道在具有真实业务规则的真实类型的应用程序中适当的域建模的任何好的例子吗?
-
事情是这样的:DDD 是一个过程,理解它的唯一方法是练习直到你“明白”:) 或参加有人解释事情的研讨会。在写作中很难(这就是弗农的书有 900 页的原因)来解释一个思考过程,而且显然一个 SO 答案的作用甚至更少。只看代码是没有用的,因为代码始终是流程的结果,并且代码是针对手头的问题量身定制的。而且我看到您仍然过于“耦合”到持久性或 UI 等细节。它们很重要,但 CQ(R)S 确实解决了所有问题 :)
标签: c# architecture domain-driven-design