C# 在分离域模型和持久性模型时,更改跟踪是如何成为一个问题的?

C# 在分离域模型和持久性模型时,更改跟踪是如何成为一个问题的?,c#,nhibernate,domain-driven-design,C#,Nhibernate,Domain Driven Design,我在这里读到这个问题: 具体来看这段代码: public class ApplicationService { private ITicketsRepository ticketsRepository; public ApplicationService(ITicketsRepository ticketsRepository) { this.ticketsRepository = ticketsRepository; } public

我在这里读到这个问题:

具体来看这段代码:

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();
    }
}
这段代码意味着有一个单独的域模型和持久性模型。我试图理解使用这种方法的局限性。在互联网上,我读到关于使用NHibernate时变更跟踪是一个问题,但我不明白为什么。更改跟踪在域模型映射回持久性模型后处理。变更跟踪如何成为一个问题?一个关于变更跟踪如何成为一个问题的实际例子将对我有所帮助

更新 请参阅下面的代码:

//Repository
public Ticket GetTicket(int ticketId)
{
    return this.ticketsRepository.GetById(ticketId);
}
我在应用程序服务中这样做:

//Application Service
Ticket ticket = applicationService.GetTicket(1);
ticket.Cost = .....
TicketEntity ticketEntity = AutoMapper.Map<TicketEntity>(ticket);
ticketEntity.DomainMethod();
ticket = AutoMapper.Map<Ticket>(ticketEntity);
//应用程序服务
票证=applicationService.GetTicket(1);
票价=。。。。。
TicketEntity TicketEntity=自动映射(票证);
tickettenty.DomainMethod();
票证=自动映射(票证有效性);
Q1)ORM的优点是否在本代码中丢失,例如变更跟踪?请注意,持久性对象从存储库返回,然后映射到域对象,然后再映射回同一持久性对象


问题2)NHibernate如何跟踪更改,即它如何知道Ticket(持久化对象)是数据库中的Ticket 1。我想这不仅仅取决于ID。

变更跟踪没有问题。域与持久性的混合是不可能的。“域模型”主要是一些易于映射到表的数据结构。在许多域中,您可能要处理99%附加了一些规则的数据结构。在这些情况下,您的域模型看起来与持久性模型几乎相同

但是再往上一点,在更抽象的层次上,域模型主要建模业务行为,状态(数据)只是一个工件。此外,它还从业务的角度(功能)看待问题

持久性模型是关于存储状态的,即数据的结构是易于检索的。对于包含许多概念及其特定模型和用例特定业务规则的具有复杂功能的域,生成的模型与持久化状态大不相同

ORM如何跟踪变化只是一个与DDD无关的实现细节,但是如果领域足够丰富,那么简单的CRUD解决方案,尤其是领域模型=状态+行为a.k.a类的心态,就会成为一个障碍。带或不带ORM


对于域=98%持久性模型的应用程序,没有问题,您可以使用任何您想要的ORM。

更改跟踪没有问题。域与持久性的混合是不可能的。“域模型”主要是一些易于映射到表的数据结构。在许多域中,您可能要处理99%附加了一些规则的数据结构。在这些情况下,您的域模型看起来与持久性模型几乎相同

但是再往上一点,在更抽象的层次上,域模型主要建模业务行为,状态(数据)只是一个工件。此外,它还从业务的角度(功能)看待问题

持久性模型是关于存储状态的,即数据的结构是易于检索的。对于包含许多概念及其特定模型和用例特定业务规则的具有复杂功能的域,生成的模型与持久化状态大不相同

ORM如何跟踪变化只是一个与DDD无关的实现细节,但是如果领域足够丰富,那么简单的CRUD解决方案,尤其是领域模型=状态+行为a.k.a类的心态,就会成为一个障碍。带或不带ORM


对于域=98%持久性模型的应用程序,没有问题,您可以使用任何您想要的ORM。

来自@MikeSW的答案中的大部分细节都是正确的;我只是不同意变更跟踪。我的答案更多的是NHibernate而不是DDD

是的,更改跟踪将是一个问题,但这取决于
i会话的管理方式。此外,不仅更改跟踪,还将影响NHibernate的其他特性,如会话级缓存、延迟加载等

让我们假设
ISession
是在请求级别管理的,即每个请求一个
ISession
。下面提到的所有活动都是单个请求的一部分

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

    return domainModel;
}

public void SaveTicket(TicketEntity ticketEntity)
{
    Ticket ticket = //Here, you have to map TicketEntity to Ticket
    this.ticketsRepository.Save(ticket);
}
现在,以下是同一请求中应用程序中的某个地方的代码:

TicketEntity ticketEntity = applicationService.GetTicket(1);
ticketEntity.Cost = .....
.....
.....
applicationService.SaveTicket(ticketEntity);
NHibernate具有跟踪
票证中发生的更改的能力,但这种能力在这里没有用处<代码>票证
在从
GetTicket
返回时丢失,而新的
票证
保存票证
时创建。NHibernate的更改跟踪功能根本不被使用,即使
ISession
处于请求级别并且能够看到更改的发生

以下代码(绕过域模型)将正确跟踪更改:

public Ticket GetTicket(int ticketId)
{
    return this.ticketsRepository.GetById(ticketId);
}
以下是如何获取和修改
票证的方法:

Ticket ticket = applicationService.GetTicket(1);
ticket.Cost = .....
.....
.....
现在,您不需要调用
SaveTicket
;相反,您可以在应用程序中检测到内频的某个位置刷新
ISession

在这种情况下,NHibernate的更改跟踪跟踪对
Ticket
所做的更改,并自动刷新这些更改

通过将持久性模型转换为域模型,我们绕过了NHibernate的这种能力,因为持久性模型永远不会改变

每种方法都有优点和缺点。参考问题

编辑:(用于您的更新

Q1):如果修改了持久性模型的相同实例,并且对相同的
ISession
可见,则新代码将受益于更改跟踪。它还将受益于会话级别