在 DDD 中具有单独的域模型和持久性模型 [英] Having Separate Domain Model and Persistence Model in DDD

查看:29
本文介绍了在 DDD 中具有单独的域模型和持久性模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在阅读有关领域驱动设计以及如何在使用代码优先方法生成数据库时实现它的内容.根据我的阅读和研究,关于这个主题有两种观点:

I have been reading about domain driven design and how to implement it while using code first approach for generating a database. From what I've read and researched there are two opinions around this subject:

  1. 有 1 个类同时用作域模型和持久性模型

  1. Have 1 class that serves both as a domain model and a persistence model

有 2 个不同的类,一个实现域逻辑,一个用于代码优先方法

Have 2 different classes, one implementing the domain logic and one used for a code-first approach

现在我知道意见 1) 据说可以简化在域和持久性模型之间没有太多差异的小型解决方案,但我认为它打破了单一职责原则,并且在 ORM 的约定干扰时引入了很多问题滴滴.

Now I know opinion 1) is said to simplify small solutions that do not have many differences between the domain and persistence models but I think it breaks the single responsibility principle and by that introduces a lot of issues when an ORM's conventions interfere with DDD.

令我惊讶的是,有许多关于如何实现意见 1) 的代码示例.但是还没有找到关于如何实现意见 2) 以及如何映射 2 个对象的单个示例.(可能有这样的例子,但我没找到 C# 的)

What is a surprise to me is there are numerous code examples of how to implement opinion 1). But a haven't found a single example of how to implement opinion 2) and how to map the 2 objects. (Probably there are such examples but I failed to find a C# one)

所以我尝试自己实现一个示例,但我不确定这是否是一个好方法.

So I tried to implement an example on my own but I am not sure if that's a good way to do it.

假设我有一个票务系统并且票证有有效期.我的域模型将如下所示:

Let's say I have a ticketing system and tickets have expiration date. My domain model will look like this:

/// <summary>
/// Domain Model
/// </summary>
public class TicketEntity
{
    public int Id { get; private set; }

    public decimal Cost { get; private set; }

    public DateTime ExpiryDate { get; private set; }

    public TicketEntity(int id, decimal cost, DateTime expiryDate)
    {
        this.Id = id;
        this.Cost = cost;
        this.ExpiryDate = expiryDate;
    }

    public bool IsTicketExpired()
    {
        if (DateTime.Now > this.ExpiryDate)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

使用实体框架作为 ORM 的持久性模型看起来几乎相同,但随着解决方案的发展,情况可能并非如此

The persistence model using Entity Framework as ORM will look almost the same but as the solution grows this might not be the case

/// <summary>
/// ORM code first Persistence Model
/// </summary>
public class Ticket
{
    [Key]
    public int Id { get; set; }

    public decimal Cost { get; set; }

    public DateTime ExpiryDate { get; set; }
}

到目前为止一切看起来都很棒.现在我不确定哪个是从存储库中获取 Ticket 持久性模型的最佳位置以及如何将其映射到 TicketEntity 域模型

Everything looking great so far. Now what I am not sure about is which is the best place to get a Ticket persistence model from the repository and how to map it to the TicketEntity domain model

我已经在应用程序/服务层完成了这项工作.

I have done this in an application/service layer.

public class ApplicationService
{
    private ITicketsRepository ticketsRepository;

    public ApplicationService(ITicketsRepository ticketsRepository)
    {
        this.ticketsRepository = ticketsRepository;
    }

    public bool IsTicketExpired(int ticketId)
    {
        Ticket persistanceModel = this.ticketsRepository.GetById(ticketId);
        TicketEntity domainModel = new TicketEntity(
            persistanceModel.Id,
            persistanceModel.Cost,
            persistanceModel.ExpiryDate);

        return domainModel.IsTicketExpired();
    }
}

我的问题是:

  1. 除了加快开发和重用代码之外,还有什么理由让意见 1) 比意见 2) 更受欢迎.

  1. Are there any reasons opinion 1) would be preferred to opinion 2) other than speeding up development and reusing code.

我的模型映射方法有什么问题吗?有什么我错过的东西会在解决方案发展时带来问题吗?

Are there any issues in my approach of mapping the models? Is there something I missed that would bring up issues when a solution grows?

推荐答案

除了加快开发和重用代码之外,还有什么理由让意见 1) 比意见 2) 更受欢迎.

Are there any reasons opinion 1) would be preferred to opinion 2) other than speeding up development and reusing code.

选项1只是因为纯粹的懒惰和想象的提高开发速度.确实,这些应用程序将更快地构建到 1.0 版.但是,当这些开发人员到达应用程序的 3.0 版本时,他们认为维护应用程序没有那么有趣,因为他们不得不在域模型中因 ORM 映射器而做出所有妥协.

Option 1 is just because of pure laziness and imagined increased development speed. It's true that those applications will get version 1.0 built faster. But when those developers reach version 3.0 of the application, they do not think it's so fun to maintain the application due to all compromises that they have had to do in the domain model due to the ORM mapper.

我的模型映射方法有什么问题吗?当解决方案增长时,我是否遗漏了什么会带来问题?

Are there any issues in my approach of mapping the models? Is there something I missed that would bring up issues when a solution grows?

是的.存储库应该负责隐藏持久化机制.它的 API 应该只适用于域实体而不是持久性实体.

Yes. The repository should be responsible of hiding the persistence mechanism. It's API should only work with domain entities and not persistence entities.

存储库负责在域实体之间进行转换(以便能够持久化它们).fetch 方法通常使用 ADO.NET 或类似实体框架的 ORM 来加载数据库对象/实体.然后将其转换为正确的业务实体并最终返回.

The repository is responsible of doing conversions to/from domain entities (to be able to persist them). A fetch method typically uses ADO.NET or an ORM like Entity Framework to load the database object/entity. Then convert it to the correct business entity and finally return it.

否则,您将强制每个服务了解有关持久性和使用域模型的知识,从而有两个责任.

Otherwise you would force every service to have knowledge about persistence AND working with your domain model, thus having two responsibilities.

如果您根据 DDD 定义使用应用程序服务,您可能需要查看命令/查询分离模式,它可以替代应用程序服务.代码变得更清晰,而且您还获得了一个更轻量级的 API,用于包装您的域模型.

If you work with application services per the DDD definition you will probably want to look at the Command/Query separation pattern which can be a replacement of the application services. The code gets cleaner and you also get a much more lightweight API wrapping your domain model.

这篇关于在 DDD 中具有单独的域模型和持久性模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆