Persistence Layer return convention issue and question - null vs. exception

I'm writing a position paper on persistence layer query returns. It deals with querying for a single object or a collection of objects and what to do if the object or collection of objects are not found in the database. I've googled many different search terms and have not come up with any authoritative references for this scenario. Do any of you know of any sources that have discussed this before?

My current logic is that when searching for a single object in a persistence layer that the persistence layer should return a simple null if the object isn't found.If searching for a collection of objects then the PL should return an empty collection object.

1.

/** Returns a list of objects that match the non-null fields in the provided example object.

This will return an empty Collection if no matching objects are found */

public Collection retrieveByExample(MyBO example);

2./** Returns a business object. This will return a null if no matching object is found */

public MyBusObject retrieveById(int aMyBusObjectId);

These two methods would not return a "checked or unchecked" exception if the object(s) are not found. I think that they are the simplest to implement and do not break the convention of not using exceptions in non exceptional situations. I don't feel that it is the persistence layer's responsibility to make a business decision on an object's existence being an exception. There are many times where applications search for an object to see if it exists or not and then proceed to create the object or use the object if it exists or doesn't. These two methods also don't force using application layers to catch or throw any declared exceptions.

Notes on scenario 1: program control flow is simple by using an iterator and hasNext(), if the collection is empty then any code that needs the objects can be skipped.

Notes on scenario 2: program control flow is simple in this case with a " != null or == null check. If the method returned an uninitialized object instead of null then the calling application would have to have additional business logic to tell whether the object was truly uninitialized or not. I can see the method having a UnexpectedMultipleBusinessObjectsFoundException if more than 1 object is found since the method is looking by primary key, but would this ever happen if searching by primary key. However in a similiar method that searches on non primary key then the UMBOFE would be warrented. Any thoughts?

Others have brought up some additional scenarios.

3./** Returns one and only one business object from persistence with a matching primary id.

If one and only one match is not found, null is returned if isLenient is true, otherwise an exception is thrown. */

public MyBusObject retrieveById(int aMyBusObjectId,boolean isLenient)throws BusinessObjectNotFoundException;

I feel this option is bad in that it forces the calling or using application layer to still declare the BusinessObjectNotFoundException.It adds bulk and unneeded complexity to the the code.

While looking at it I can see that since a caller is searching for exactly 1 object then if the query finds more than one object then a UnexpectedMultipleBusinessObjectsFoundException could be thrown. But I don't believe an NotFoundException is warranted. What are your thoughts?

Message was edited by:

smalltalk

[3779 byte] By [smalltalka] at [2007-11-26 23:44:28]
# 1

I agree with everything you have said but that doesn't help much with the authoritative figure.

You might note for the case with the primary id versus multiple return values what exactly would lead to that? Basically I can only see it as a corrupt database which should actually lead to a program exit.

However, myself dealing with that situation in multiple database layers (different languages, companies, etc) I just return the first one. In that case the database itself should be protected from that completely. And if it isn't it suggests that perhaps something was changed on purpose. There isn't any point is ceasing to do what it always did.

I will note that years ago I implemented a NotFound exception. But that was some hideous code (many levels, C++, ProC, etc) and I implemented it as a known exception to the principal that one shouldn't throw exceptions for known conditions. It just impacted to much code to try to put it in otherwise.

jschella at 2007-7-11 15:15:55 > top of Java-index,Other Topics,Patterns & OO Design...
# 2

Hibernate (for example) actually does both.

public Object get(Class clazz, Serializable id) throws HibernateException - "Return the persistent instance of the given entity class with the given identifier, or null if there is no such persistent instance. (If the instance, or a proxy for the instance, is already associated with the session, return that instance or proxy.)"

public Object load(Class theClass, Serializable id) throws HibernateException: "Return the persistent instance of the given entity class with the given identifier, assuming that the instance exists.You should not use this method to determine if an instance exists (use get() instead). Use this only to retrieve an instance that you assume exists, where non-existence would be an actual error."

Certainly get is the more commonly used of these methods.

If you are returning something like an array I believe it is always preferable to return a zero length array rather than null to save the extra client code.

YoGeea at 2007-7-11 15:15:55 > top of Java-index,Other Topics,Patterns & OO Design...
# 3

if you were to write out the use cases for the frame work woulds an object not found be and alternate or exceptional pathway.

that is does your model say ....

these objects may or may not be there, depends if you have created the record.finding or not finding an object is used to determine flow control in the normal logic of the system. return null or and empty collection, perhaps an empty single object

or

in the model this object is required to be there if it is not then there is some defect in the code or corupt data or something. this is not part of the logical business flow of the system (or sub-system) hence it is exceptional

search around for good programming practices references and look for using exceptions as control structures.

radix_zeroa at 2007-7-11 15:15:55 > top of Java-index,Other Topics,Patterns & OO Design...