如何在保存之前检查nHibernate和DDD中的唯一约束违规?

dst*_*stj 8 nhibernate domain-driven-design

我在帐户的名称上有一个帐户模型对象和一个UNIQUE约束.在域驱动设计中,使用nHibernate,插入或更新实体之前,如何检查名称的unicity ?

我不想依赖于nHibernate异常来捕获错误.我想向我的用户返回一个更漂亮的错误消息而不是模糊could not execute batch command.[SQL: SQL not available]

在问题我应该哪里进行DDD的独特检查?有人建议使用这样的规格.

Account accountA = _accountRepository.Get(123);
Account accountB = _accountRepository.Get(456);
accountA.Name = accountB.Name;

ISpecification<Account> spec = new Domain.Specifications.UniqueNameSpecification(_accountRepository);
if (spec.IsSatisfiedBy(accountObjA) == false) {
   throw new Domain.UnicityException("A duplicate Account name was found");
}
Run Code Online (Sandbox Code Playgroud)

使用规范代码:

public bool IsSatisfiedBy(Account obj)
{
   Account other = _accountRepository.GetAccountByName(obj.Name);
   return (other == null);
}
Run Code Online (Sandbox Code Playgroud)

这适用于插入,但不适用于执行更新,因为.我尝试将代码更改为:

public bool IsSatisfiedBy(Account obj)
{
   Account other = _accountRepository.GetAccountByName(obj.Name);

   if (obj == null) {  // nothing in DB
      return true;
   }
   else {              // must be the same object.
      return other.Equals(obj);
   }
}
Run Code Online (Sandbox Code Playgroud)

问题是nHibernate在执行时会GetAccountByName()向数据库发出更新以恢复可能的重复...

return session.QueryOver<Account>().Where(x => x.Name == accntName).SingleOrDefault();
Run Code Online (Sandbox Code Playgroud)

所以我该怎么做?规范不是正确的方法吗?

谢谢你的想法!

小智 5

我不喜欢数据访问的规范模式,它似乎总是跳起来完成任何事情.

但是,你的建议,实际上归结为:

  1. 检查它是否已存在.
  2. 如果没有,则添加; 如果有,则显示用户友好的消息.

......几乎是完成任务的最简单方法.

如果您的数据库及其.NET客户端正常传播侵犯唯一约束的表和列,则依赖于数据库异常是另一种方法.我相信大多数司机都没有这样做(??),因为他们只是抛出一个ConstraintException说法"在表格ABC上违反了约束XYZ".你当然可以在你的唯一约束命名上有一个约定来说出类似于UK_MyTable_MyColumn的东西,并使用字符串魔法来拉出表和列名.

NHibernate有一个ISQLExceptionConverter你可以Configuration在设置NHibernate时插入对象的东西.在此内容中,您将接触到.NET数据客户端的异常.您可以使用该异常来提取表和列(可能使用约束名称?)并使用用户友好消息抛出一个新的Exception.

使用数据库异常方式更具性能,您可以将大量检测唯一约束违规代码推送到基础架构层,而不是逐个处理每个代码.

使用query-first-then-add方法值得指出的另一件事是,为了完全事务安全,您需要将事务级别升级为可序列化(这使得最差的并发性)完全是防弹的.您是否需要完全防弹,取决于您的应用需求.

  • 谢谢 Thilak,我会看看`ISQLExceptionConverter`。我找到了 [这篇博文](http://fabiomaulo.blogspot.com/2009/06/improving-ado-exception-management-in.html) 和 [这个其他问题](http://stackoverflow.com/questions /1524167/custom-exception-using-nhibernate-isqlexceptionconverter) 以帮助处理 `ISQLExceptionConverter` (2认同)