我在帐户的名称上有一个帐户模型对象和一个UNIQUE约束。在域驱动设计中,使用nHibernate,在插入或更新实体之前,我应该如何检查名称的 ?
我不想依赖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);
}
}
问题是nHibernate在执行GetAccountByName()
以恢复可能的重复时会向数据库发出更新...
return session.QueryOver<Account>().Where(x => x.Name == accntName).SingleOrDefault();
那么,我该怎么办?规范不是是正确的方法吗?
感谢您的想法!
答案 0 :(得分:5)
我不喜欢数据访问的规范模式,它似乎总是跳起来完成任何事情。
然而,你所建议的,实际上只归结为:
......几乎是完成任务的最简单方法。
如果您的数据库及其.NET客户端正常地传播表格,那么依赖数据库异常是另一种方法。侵犯唯一约束的列。我相信大多数司机不这样做(??),因为他们只是抛出一个通用的ConstraintException
,上面写着“约束XYZ在表ABC上被违反”。你当然可以在你的唯一约束命名上有一个约定来说出像UK_MyTable_MyColumn这样的东西,然后用字符串法术来拉动表格和放大器。专栏名称。
NHibernate有ISQLExceptionConverter
,你可以在设置NHibernate时插入Configuration
对象。在此内容中,您将接触到.NET数据客户端的异常。您可以使用该例外来提取表格和列(可能使用约束名称?)并使用用户友好消息抛出一个新的异常。
使用数据库异常方式更具性能,您可以将大量 detect-unique-constraint-violation 代码推送到基础架构层,而不是逐个处理每个代码。 / p>
使用 query-first-then-add 方法值得指出的另一件事是,为了完全事务安全,您需要将事务级别升级为可序列化(这给出了最差的并发性)完全是防弹。无论您是否需要完全防弹,都取决于您的应用需求。
答案 1 :(得分:-2)
您需要使用Session.FlushMode模式处理它以设置为FlushMode.Commit,并在所有更新都被触发时使用事务来回滚。