使用POCO类作为域类,但使用自定义链接getter和setter?

时间:2014-06-05 01:03:29

标签: c# entity-framework domain-driven-design poco

我最近了解到(使用Entity Framework时)设计代码优先是一个好主意,POCO类也与原始域类逻辑混合在一起。

所以我决定使用这个新想法。之前(作为示例)我有一个名为DatabasePerson的POCO类和一个名为Person的域类。我现在正尝试将这些合并为一个,这样我就可以让Entity Framework更好地管理我的存储库,并更轻松地管理对域层的更改。

现在,在我的DatabasePerson POCO课程中,我有一个指向DatabaseAccount POCO课程的链接。同样,我的Person域类具有指向Account域类的链接。

在Entity Framework中,为了允许延迟加载这些类型的链接,我将链接属性声明为虚拟(如DatabasePerson类中所示),如下所示:

public virtual DatabaseAccount Account { get; set; }

但是,如果我想更改帐户的设置或获取方式,以及尝试将其设置为null时如何处理异常,该怎么办?如何确保这不会与Entity Framework添加到表中的任何内容冲突?

这是我的域类'链接:

public Account Account {
    get {
        //maybe do some other stuff here.
        return account;
    }
    set {
        if (value == null) throw new ArgumentNullException("value");

        account = value;

        //maybe do some other stuff here.
    }
}

我想以某种方式保持这种形式的可定制性,但也有延迟加载。这可能吗?

1 个答案:

答案 0 :(得分:2)

延迟加载与域驱动设计的概念冲突,尤其是Aggregates的概念。从存储库检索和更新聚合应该是单个操作。根据无所不在的语言中的规范,聚合需要完整。引入延迟加载会破坏此规则,因为聚合不完整(或者这可能表示您未正确定义聚合)。

除此之外,您还违反了DDD的核心原则之一;您正在设计具有技术问题(实体框架,数据库,延迟加载等)的强大影响的域。引入这些基础设施“泄漏”将限制您做出设计决策的方式。实体和价值对象构成了您域名的绝对核心。它们是彼此交互的真实世界对象。持久性无知是设计良好领域模型的关键。

我将举一个关于聚合的简短例子,但如果你想更好地掌握这个概念,你需要做更多的阅读。

假设您已确定Order实体是包含OrderOrderLine的聚合的根(Order可以包含1个或多个OrderLine OrderLine 1}}实体)。这个决定可以基于很多原因,其中一些是:

  • Order无需独立检索或引用Order
  • Order应负责更改其OrderLine'集合'
  • OrderLines及其Order应具有交易一致性

从存储库中获取OrderLines时,此聚合将在单个工作单元中形成。所有Person将使用其订单获取并返回。保存或更新时,聚合也会保留在单个工作单元中。这可确保所有实体(及其关系)保持一致,并且不会违反“业务规则”。

在您的情况下,Accounts及其Account很可能不属于单个聚合。我假设您需要访问一个人的帐户而无需检索该人本身(可能使用身份)。我假设您将要引用聚合外部的特定帐户(只能从聚合外部引用聚合根)。我还假设Person可以独立于{{1}}进行更改。也许你不希望它属于Person聚合的另一个原因是由于性能原因(是的,有时我们必须务实而不是纯粹!)。以上所有完全取决于您的要求。

就个人而言,我相信将您的数据实体(通常是使用Entity Framework或其他一些持久性工具从您的数据库直接映射)与您的域实体/值对象分开。这使您可以完全隔离与数据库相关的结构,框架和约束来设计域。