How to handle "no results" case?

How to handle "no results" case?

Old forum URL: forums.lhotka.net/forums/t/4342.aspx


GlennA posted on Wednesday, February 13, 2008

Doing some initial prototyping with CSLA...

How might one best handle a call to the static factory method GetMyClass(...) when no results are returned (often a real scenario).    As I have it coded now (using CodeSmith templates as a starting point), an InvalidOperationException is thrown when trying convert data that doesn't exist in the SafeDataReader into the private members of the class.

One could catch the InvalidOperationException and handle it (return null?), but I'm worried that this might mask other problems throwing the same exception.  How do you experts do it?

This has likely come up before, but I was unable to find it by searching the forum.

TIA,

Glenn

 

 

 

SomeGuy replied on Wednesday, February 13, 2008

Generally, I have users select an object from a list, so it's existance is almost guaranteed. I could see a MRU List or opening the last open object situation where the object could have been deleted in the mean time. In those cases, I would problaby do a if (MyClass.Exists(classId)) first rather than a check for a null return value or exception.

Also, most of the examples do a simple dr.Read(); and then get the values, simply checking the return value from that would allow you to gracefully exit. You might have to set a private flag to allow the Factory method to return null instead of an empty object

E

 

ajj3085 replied on Wednesday, February 13, 2008

I usually throw a custom exception, so that I know the reason is that no results were found instead of maybe something else failing and throwing an InvalidOperationException.

JoeFallon1 replied on Wednesday, February 13, 2008

When this question came up 4 years ago the community was split between returning an exception and returning a New object. I went with returning a New object. It works out for me.

But Rocky is in the Exception camp and so subsequent changes to CSLA have caused me a little pain. e.g. Rocky moved MarkOld into the frameowrk instead of leaving it as a developer step to implement for Root objects. This has caused timing issues and so I have had to comment it out and use my older style. Rocky has run into a problem with it in WPF too so it may not have been the best move. But it is there now so...

I recommend you throw some sort of exception when you check If dr.Read = True. This seems to be the current consensus.

Joe

 

ajj3085 replied on Wednesday, February 13, 2008

JoeFallon1:
But Rocky is in the Exception camp and so subsequent changes to CSLA have caused me a little pain. e.g. Rocky moved MarkOld into the frameowrk instead of leaving it as a developer step to implement for Root objects. This has caused timing issues and so I have had to comment it out and use my older style. Rocky has run into a problem with it in WPF too so it may not have been the best move. But it is there now so...


What issue has this caused in WPF?  Seems like WPF wouldn't get involved until after the DP returns, which is after any calls to MarkOld would be performed (manually or automatically by Csla).

JoeFallon1 replied on Wednesday, February 13, 2008

See Page 100 of Using CSLA 3.0 (VB edition).

In DataPortal_Update Rocky calls MarkOld() explicitly. This is because it needs to be marked old *before* ExecuteWorkflow is called. So the framework call to MarkOld happens *too late* in the process.

This is similar to my logic which says I need to explicitly call MarkOld on my root BOs because when I call CheckRules some of the rules need to know if the object is New or Old. So again, the framework call hapens too late in the process.

Therefore, I think the call to MarkOld should be removed from the framework as it interferes with the correct working of many scenarios. Or if I call it explicitly then the call is redundant.

Joe

 

 

 

ajj3085 replied on Wednesday, February 13, 2008

Oh... WF.  I looked up that sample in the ebook.  Given the explaination, it seems that the call to ExecuteWorkflow could be moved to the DataPortal_OnDataPortalInvokeComplete override, and that would remove the need for the explicit MarkOld. 

Of course, this also seems to be an edge case, and calling MarkOld explicitly in the DataPortal method doesn't hurt anything.  In the normal case, its one less thing for me and other Csla-ers to forget. 

rsbaker0 replied on Wednesday, February 13, 2008

Hmmm.

We just return null rather than an object (from our factory "getter") I'm not sure why this would be bad, but it makes writing code quite simple (e.g.)

if (ObjectClass.Get(criteria) == null)...

ajj3085 replied on Thursday, February 14, 2008

Can't say there's anything wrong with that either.  At one company, we had a rule "don't use exceptions to control logic."  Your method would fit that line of thinking.  It was always a tough call though; if you always expected to get something back then an exception would be fine.  But if no results is a "normal" case, then returning null would be the proper answer.

In my case, you open the editable object by specifying the read only object.  Normally, searches give back a result set (which can be empty).  You then open the editable version by passing the readonly to the factory, so in my case it doesn't make sense to return null; its already been established that the data exists.

rsbaker0 replied on Thursday, February 14, 2008

^^^^^

After I posted the above, I remembered that null causes us issues if it's for a child of a bound root object. It's not too bad, but we have to test for it and substitute an "empty" object for the bindingsource when it happens , so it does have some consequences.

RockfordLhotka replied on Thursday, February 14, 2008

ajj3085:
Oh... WF.  I looked up that sample in the ebook.  Given the explaination, it seems that the call to ExecuteWorkflow could be moved to the DataPortal_OnDataPortalInvokeComplete override, and that would remove the need for the explicit MarkOld. 

Of course, this also seems to be an edge case, and calling MarkOld explicitly in the DataPortal method doesn't hurt anything.  In the normal case, its one less thing for me and other Csla-ers to forget. 

Joe's going to love 3.5 - or not...

In 3.5 the data portal now supports saving child objects - which simplifies your code a lot - no need to override DP_U in a list, and much more standard coding in editable child objects.

But of course the data portal now calls MarkOld() (, etc.) on the child objects just like it does for root objects. That's part of making the code more standard, which I think is a powerful benefit.

Fortunately, you don't have to use the child management - the 2.0/3.0 style coding approach works fine.

I made sure to support both because the new way is slower, but oh so much nicer - but I wanted to make sure people could choose between performance/flexibility and simplicity/productivity Big Smile [:D]

ajj3085 replied on Friday, February 15, 2008

Yes, I'm actually looking forward to the code savings.  A lot of my problems lately are forgetting some of the plumbing I now have to do.. listening for changes from child objects specifically.

One thing I'm hoping will still work; there is a case where I create a new object when one doesn't exist.  In the end, the object must be New, but also Not Dirty.  These children are created from a cross join query, where sometimes the row data which would represent the child is not there at all (because it was never defined). 

(The use case is that a product is being edited, and there's a grid for entering the prices on various price lists [domestic, foreign, any other's the users create].  The price list MUST show in this grid, or the use wouldn't be able to enter a price on the product edit screen or the price list edit screen fro that matter.  Its a typical many to many scenario.)

This I realize is also an edge case, and its good you're leaving both styles in Csla since if I can't get things to work with the new managed stuff I can just leave this particular class alone.

Andy

JoeFallon1 replied on Friday, February 15, 2008

Andy

That's really funny:

"there is a case where I create a new object when one doesn't exist.  In the end, the object must be New, but also Not Dirty. "

This is exactly my coding style. I test for existence and then branch to DP_Create or stay in DP_Fetch. The problem is that the Framework now calls MarkOld for you because it started in DP_Fetch and doesn't care that you don't want an old object - you now want a new one.

This is why manually coding the MarkOld and MarkNew in the classes is a "better way to go" in my opinion. At least for this coding style. I would have to re-write hundreds of classes and do a massive amount of re-testing to "get in alignment" with the currently accepted way of handling this.

That isn't going to happen. I think I will just continue to comment out the calls to MarkOld in the framework and call it a day. <g>

Joe

 

ajj3085 replied on Friday, February 15, 2008

Like I said its an edge case that happens on exactly two use cases, and exactly two classes don't follow the normal pattern.  For the hundreds of other types I have what Csla does is exactly correct. 

Much more common than the edge case though is me not wiring up the plumbing between parents and children and hitting bugs because of it.  Worse, when I did have to switch to remoting, I had a lot of retesting to do because I wasn't in the habit of writing that plumbing code everywhere it is needed.  Csla 3.5 will allow me to remove all of that code and Csla will handle those tasks for me, resulting in me having to write less code and there will be less bugs as well.

The more Csla details that Csla handles for me the better, because writing the MarkOld code and in children right now, finding all the places I have forgotten to write the call leading to weird bugs, the better. Tracking down yet another bug because I forgot a MarkOld is not what I find interesting.

Copyright (c) Marimer LLC