【问题标题】:Mapping a Domain Model to the database with EF Fluent API使用 EF Fluent API 将域模型映射到数据库
【发布时间】:2013-12-13 11:55:29
【问题描述】:

下面是通过Entity Framework 6 Fluent API直接映射到数据库的Project代码优先类:

public class Project
{
    public Project()
    {}

    public int ProjectId { get; set; }

    public string Name { get; set; }

    public bool IsActive { get; set; }

    public ICollection<ProjectVersion> ProjectVersions { get; set; }
}

领域驱动设计中的贫血模型是一种反模式。我想在我的 域模型 中使用同一个类,而不是创建一个单独的 Project 域类并且必须在存储库中执行两者之间的复杂映射(以及我们拥有的数百个其他模型)。

这就是Project 作为领域模型类的样子:

public class Project
{
    private readonly List<ProjectVersion> projectVersions;

    public Project(string name, string description)
    {
        Name = name;
        Description = description;
        projectVersions = new List<ProjectVersion>();
    }

    public int ProjectId { get; private set; }

    public string Name { get; set; }

    public bool IsActive { get; private set; }

    public IEnumerable<ProjectVersion> ProjectVersions 
    { 
        get
        {
            return projectVersions;
        }
    }

    public void AddVersion(ProjectVersion version)
    {
        projectVersions.Add(version);
    }
}

From what I have read,我可以使用 EF 的 Fluent API 映射到私有字段。

这里有什么不足吗?我走的是不必要的捷径吗?

我能预见的唯一问题是,当业务域模型本质上由来自两个或多个数据实体的数据组成时。

【问题讨论】:

    标签: entity-framework domain-driven-design automapper domain-model onion-architecture


    【解决方案1】:

    我认为您在这种方法中犯了一个错误。我认为您应该将域模型的关注点与实体模型的关注点分开。 Bob 叔叔在这里写了一篇奇怪但很中肯的博客文章:Dance You Imps!(说真的,这是一篇奇怪的文章。)ORM 的工作是充当数据库的合同。您的域模型的工作是提供功能。简而言之,您应该让 Entity Framework 以它想要的方式运行。如果你想做 DDD,写一个映射层来将 EF 模型转换为你的 Domain 模型。

    【讨论】:

    • 好吧,我无法反驳这篇文章。但是,我可以声明,如果您确实公开了您的属性,并且您确实打算使用映射到数据库的模型,那么我认为没有理由不简单地将您的域实体的属性映射到数据存储。但是,除非 EF6 现在可以处理带参数的构造函数,否则上述示例将不起作用。
    【解决方案2】:

    这里有什么不足吗?

    可能。

    确实,EF 可以寻址私有成员,因此如果您愿意,它可以通过加载的ProjectVersions 集合实现Project。它不会为此使用AddVersion 方法(它甚至不知道它存在),但它会将对象添加到projectVersions 成员。

    在您想要通过方法添加版本的应用程序代码中。不过这种AddVersion 方法可能存在一些问题。

    • 您始终可以添加ProjectVersion,但您永远无法确定它是否会被存储,因为EF 跟踪添加的projectVersions 必须已经加载。但是,您不希望域实体负责从数据库中加载其自己的子实体。所以AddVersion 赋予班级一项无法完全履行的职责。
    • 调用AddVersion 可以在对象的生命周期内的任何时刻发生。通常这将比创建和跟踪它的上下文的生命周期更长。所以如果集合还没有加载,你不能依赖延迟加载来救援。 (顺便说一下,ProjectVersions 应该是 virtual ICollection)。
    • 结论是,您总是必须急切地加载projectVersions(通过Include)以保证AddVersion 正常工作。因此,您的应用程序中存在两个不明显相关的代码段之间的依赖关系,这是潜在的错误来源。
    • 当需要保存Project 时,您必须将其附加到上下文中并找出应该将哪个ProjectVersion 标记为插入,哪个标记为更新(甚至还没有RemoveVersion 方法。

    总而言之,在服务方法中添加版本要简单得多,该方法在上下文的生命周期内执行所有必需的操作。添加的版本将被标记为自动插入。同样,任何更新和删除的版本都会被正确标记。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      • 2019-01-30
      • 2015-11-12
      • 2014-07-22
      • 1970-01-01
      • 2011-07-15
      相关资源
      最近更新 更多