良好的设计可以跟踪域模型中的更改
本文关键字:模型 跟踪 | 更新日期: 2023-09-27 18:26:06
我们有两个独立的现有应用程序,它们只能通过总线消息系统和数据库进行通信。现在,我们想通知第二个应用程序在数据库更新之前或之后对第一个应用程序中的域模型所做的任何更改:一旦我们知道有真正的更改要保存在存储中或刚刚保存,我们就想向单独的应用程序发送特定的消息。消息不指示进行了何种更改。
一些注意事项:
- 我们希望精简我们的域模型,我的意思是内部没有特定的业务逻辑,同时我们不想向我们的数据层(存储库类列表)添加服务引用
- 理想情况下,若数据库并没有真正的更改,即使调用了存储库的Update方法,我们也不想发送消息
- 若消息在数据提交到数据库之前发送,即使它们最终被拒绝,也没关系
- 我们的域模型由具有数十个属性的数十个对象组成,因此将OnPropertyChanged添加到每个属性将花费大量时间
- 我们绝对不想在存储级别上实施通知系统
- 我们希望以任何开发人员都无法绕过此通知机制的方式构建我们的应用程序设计
在应用程序设计方面,您建议我们在本案例中使用哪些方法?数据层通过总线系统提交此类通知是否是一种良好的做法?我们怎么能知道数据实际上发生了变化:我们能通过NHiberate会话知道吗,还是跟踪域模型内部的变化?
数据层通过总线系统提交此类通知是否是一种良好的做法?
不,不是。尽管有些框架支持开箱即用,但单独使用或编写通常是错误的。这里的问题有两个方面——
- YAGNI-当你提前设计一个系统时,你往往会用高估的机制来淹没它,这反过来又会影响系统的效率和简单性
- 上下文是关键!有一个存储库在没有上下文的情况下通知它所做的一切,这太笼统了。考虑在向表中插入行以更改UI时发出通知,现在考虑从云中同步数据。数据到数据库的膨胀和UI刷新率之间有很强的耦合,这显然是两件不同的事情。解决这个问题并保持连贯性成为一种阻力
我们怎么能知道数据实际上发生了变化:我们能通过NHiberate会话知道吗,还是跟踪域模型内部的变化?
你对需求和这个问题的表述有些不一致。您是这样呈现的-"如果消息在数据提交到数据库之前发送,即使它们最终被拒绝,也没关系"然后您说知道数据是否实际更改是相关的。
无论如何,如果您将数据直接保存到DB,它通常会返回一些指示,比如修改的行数。当使用像NHibernate这样的ORM框架时,您通常可以立即提交事务并获得相同的指示。
在这两种方式中,如果另一个应用程序正在从同一个数据库中检索数据,则应该只让另一个程序知道数据在数据库中实际更改的时间。
在应用程序设计方面,您建议我们在本案例中使用哪些方法?
我们通过将事件发布为逻辑过程的一部分而不是持久性的一部分来解决此问题,因为您可能有一些不需要通知的操作。如果您仍然想在数据方面做到这一点,我不建议在您的存储库中对其进行硬编码,而是使用Martinfowler的工作单元或事务脚本模式。它们将允许您决定哪些数据事务应该发布事件,哪些不应该,以及何时发布。
数据层通过公共汽车系统?
不需要,但如果您需要为每一次更改发送这样的通知,并且如果您可以在不更改所有存储库的情况下将这些事件绑定到系统的管道中,那就可以了。
我们怎么知道数据实际上发生了变化:我们是通过NHiberate会话知道还是跟踪域内的变化模型
这个问题最简单的解决方案是使用拦截器或事件。像这样的东西应该能解决你的问题,
事件
(完整示例请参考)
public class ChangeEventListener : IFlushEntityEventListener
{
public SetModificationTimeFlushEntityEventListener()
{
CurrentDateTimeProvider = () => DateTime.Now;
}
public void OnFlushEntity(FlushEntityEvent @event)
{
var entity = @event.Entity;
var entityEntry = @event.EntityEntry;
if (entityEntry.Status == Status.Deleted)
{
//raise event
}
var trackable = entity as ITrackModificationDate;
if (trackable == null)
{
return;
}
if (HasDirtyProperties(@event))
{
//raise event
}
}
}
拦截器
public class NotificationInterceptor : EmptyInterceptor
{
public override bool OnFlushDirty(object entity,
object id,
object[] currentState,
object[] previousState,
string[] propertyNames,
IType[] types)
{
//do check for changed states by comparing current and previous values, and raise event if changed
return true
}
}