我有一个实体对象,通过FK引用其他实体对象。在我的示例batch.Equipment引用设备实体。如果我尝试使用此代码插入对象:
var batch = new Batch();
batch.Equipment = session.Load<Equipment>(someEquipmentId);
session.Save(batch);
一切正常,但我希望如果碰巧那些带有someEquipmentId的设备不存在,nhibernate会抛出ObjectNotFoundException,而是抛出GenericAdoException,说有违反外键,这是很明显,因为someEquipmentId并不存在于数据库中,所以批量不能插入那个设备ID,但我认为nhibernate会为我处理这个。
所以问题是,是否有一种方法(一些映射属性或其他东西)会使nhibernate在这种情况下抛出ObjectNotFoundException,或者我是否必须执行session.Get(someEquipmentId)并将其检查为null?我的意思是我可以做到这一点,但是在我看来,它给了我不必要的db往返,感觉就像是重复的代码而且我不喜欢检查每个像这样的引用,因为有很多这样的实际发生的情况很少见,真的例外,我更喜欢把它整个放在try catch中并在一个地方处理ObjectNotFoundException。我需要它向用户报告,为什么插入失败,指定哪个实体不存在(要求)。
答案 0 :(得分:1)
这里的答案非常简单:Load(id)
是一份合约,代表现有价值。因此,如果传递的 id 值可能错误(不存在),则您不信任它:必须使用Get(id)
并检查null
。
请阅读这篇文章:Ayende - NHibernate – The difference between Get, Load and querying by id,一些摘录:
Get()
和Load()
出于某种原因,它们提供了一种通过主键获取实体的方法。这对于几个方面很重要,最重要的是,它意味着NHibernate可以对此过程应用相当多的优化。但另一方面,Get和Load之间存在显着(和微妙)差异。
加载永远不会返回null。它将始终返回实体或抛出异常。因为这是我们拥有的合同,所以允许Load在调用它时不会访问数据库,而是可以自由返回代理。
...
然而,获取是不同的。如果对象不存在,Get将返回null。由于这是它的契约,它必须返回实体或null,因此如果不知道实体存在,它就不能给你代理。 Get通常会导致对数据库的选择,但它会首先检查会话缓存和第二级缓存以获取值。
答案 1 :(得分:0)
session.Load(id)
永远不会返回null。它将在您的情况下返回代理,因为id不存在。加载的目的是不打击数据库,而是从缓存加载对象。
“Load将永远不会返回null。它将始终返回一个实体或抛出异常。因为这是我们拥有的合同,所以当你调用它时,Load不允许命中数据库,它是免费的改为代理。
为什么这有用?好吧,如果您知道数据库中存在该值,并且您不想支付额外的选择以获得该值,但是您希望获得该值以便我们可以将该引用添加到对象,则可以使用Load to这样做:
s.Save(
new Order
{
Amount = amount,
customer = s.Load<Customer>(1)
}
);
上面的代码不会导致对数据库的选择,但是当我们提交事务时,我们将CustomerID列设置为1.这就是NHibernate在为您提供直接工作的相同优化优势时维护OO外观的方式低级API。“ - Ayende Rahien
http://ayende.com/blog/3988/nhibernate-the-difference-between-get-load-and-querying-by-id