2011-10-06 119 views
8

我有一个账户模型对象和对账户名称的唯一约束。在域驱动设计中,如果使用nHibernate,我应该如何在之前检查名称的唯一性如何在保存前检查nHibernate和DDD中的唯一约束违规?

我不想依赖nHibernate异常来捕获错误。我想向我的用户返回一个比晦涩难懂的错误消息could not execute batch command.[SQL: SQL not available]

在问题Where should I put a unique check in 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"); 
} 

与规格代码:

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

这适用于刀片,但不这样做,因为更新的时候。我试过的代码更改为:

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); 
    } 
} 

是,当执行GetAccountByName()恢复可能重复NHibernate的会发出一个更新到数据库的问题...

return session.QueryOver<Account>().Where(x => x.Name == accntName).SingleOrDefault(); 

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

感谢您的想法!

回答

5

我不是数据访问规范模式的忠实粉丝,它总是像跳跃的箍环来完成任何事情。

但是,你有什么建议,这实际上只是归结为:

  1. 检查,如果它已经存在。
  2. 如果没有,则添加;如果有,请显示用户友好的信息。

...几乎是最简单的方法来完成它。

如果您的数据库和它的.NET客户端优雅地传播表(&)侵犯唯一约束的列,则依赖于数据库异常是执行此操作的另一种方式。我相信大多数司机不这样做(??),因为他们只是抛出一个通用的ConstraintException,表示“在表ABC上约束XYZ被违反”。你当然可以有一个关于你的独特约束命名的约定来说一些像UK_MyTable_MyColumn这样的字符串,并且将字段名称从列表&中取出。

NHibernate有一个ISQLExceptionConverter,你可以在设置NHibernate时插入到Configuration对象中。在这里面,你会暴露于.NET数据客户端的异常。您可以使用该例外来提取表&列(可能使用约束名称?)并使用用户友好的消息抛出一个新的Exception。

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

另一件事值得与查询第一,然后加方法指出的是,你需要在事务级别升级到序列化(这给最坏的并发性)是完全防弹说是完全的交易安全。无论您是否需要完全符合防弹要求,都取决于您的应用需求。

+1

谢谢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' – dstj

-2

您需要使用Session.FlushMode模式来处理它,以设置FlushMode.Commit并使用事务来回滚,如果在所有更新触发。

+0

我试着为ISession设置FlushMode来提交,但我得到了同样的结果。更新在选择之前发送到数据库并引发异常... – dstj

+1

@dstj 1,您是否使用Transaction? 2,如果您使用FlushMode进行提交,我相信只有在调用transaction.Commit之前,数据才会更新。 3,使用NHProfiler找出什么时候更新被解雇。 –