MSkuta
MSkuta

Reputation: 1783

Nhibernate throws GenericAdoException instead I would expect ObjectNotFoundException

I have a entity object, that has via FK referened other entity object. In my example batch.Equipment references Equipment entity. If I try to insert the object using this code:

var batch = new Batch();
batch.Equipment = session.Load<Equipment>(someEquipmentId);
session.Save(batch);

Everything is working fine, but I would expect that, if it happens that Equipment with the someEquipmentId doesn't exist, nhibernate would throw me ObjectNotFoundException, instead it throws GenericAdoException saying that there was violation of foreign key, which is obvious because the someEquipmentId doesn't exist in database, so the batch cannot be inserted with that equipment id, but I thought nhibernate would handle that for me.

So the question is, is there a way (some mapping attributes or something) that would make nhibernate throw ObjectNotFoundException in such cases, or do I have to do session.Get(someEquipmentId) and check it for null? I mean I can do that, but it gives me in my opinion unecessary db roundtrips, feels like repetitive code and I don't like checking for every reference like that as there are many and the cases where this actually happens are rare and really exception, I prefer putting it whole in try catch and processing the ObjectNotFoundException in one place. I need it to report back to user, why the insert failed, specifying which entity doesn't exist (requirement).

Upvotes: 1

Views: 559

Answers (2)

sm_
sm_

Reputation: 2602

session.Load(id) will never return null. It will return a proxy instead in your case, because the id doesn't exist. Load is purposed to NOT hit the database, but to load the object from cache.

"Load will never return null. It will always return an entity or throw an exception. Because that is the contract that we have we it, it is permissible for Load to not hit the database when you call it, it is free to return a proxy instead.

Why is this useful? Well, if you know that the value exist in the database, and you don’t want to pay the extra select to have that, but you want to get that value so we can add that reference to an object, you can use Load to do so:

s.Save(
    new Order
    {
        Amount = amount,
        customer = s.Load<Customer>(1)
    }
);

The code above will not result in a select to the database, but when we commit the transaction, we will set the CustomerID column to 1. This is how NHibernate maintain the OO facade when giving you the same optimization benefits of working directly with the low level API." - Ayende Rahien

http://ayende.com/blog/3988/nhibernate-the-difference-between-get-load-and-querying-by-id

Upvotes: 0

Radim K&#246;hler
Radim K&#246;hler

Reputation: 123891

The answer here is pretty straightforward: Load(id) is a contract, representing the existing value. So, if the passed id value could be wrong (not existing), you do not trust it: you must use Get(id) and check the null.

Please, do read this article: Ayende - NHibernate – The difference between Get, Load and querying by id, some extract:

Get() and Load() are here for a reason, they provide a way to get an entity by primary key. That is important for several aspects, most importantly, it means that NHibernate can apply quite a few optimizations for this process.

But there is another side to that, there is a significant (and subtle) difference between Get and Load.

Load will never return null. It will always return an entity or throw an exception. Because that is the contract that we have we it, it is permissible for Load to not hit the database when you call it, it is free to return a proxy instead.

...

Get, however, is different. Get will return null if the object does not exist. Since this is its contract, it must return either the entity or null, so it cannot give you a proxy if the entity is not known to exist. Get will usually result in a select against the database, but it will check the session cache and the 2nd level cache first to get the values first.

Upvotes: 1

Related Questions