When Child_Fetch returns an Invalid Child

When Child_Fetch returns an Invalid Child

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


Jav posted on Thursday, August 05, 2010

When the code reaches Child_Fetch, the child has alread been created.  If now the DB does not return a valid child, the object graph will still have this invalid child. That has always been the Csla behavior. 

Now with FieldManager available to load and update children, is there a standard method of dealing with this kind of child objects?

Jav

Jav replied on Monday, August 16, 2010

Does anyone have any idea how to handle this situation.  Child objects are loaded using the Parent's PK.  If the DB returns nothing, you will have a child, marked Old but with a PK of zero and every other field blank - which will cause wierd behavior down the line.

1. One could test for the existence of the child from the Factory method before calling Fetch
2. One could examine the PK of every child object in the Child_Fetch method, and if zero or guid.empty etc, one could mark the child New and make it eligible for insertion.

Is there some other standard way yo handle this?

Jav

tmg4340 replied on Monday, August 16, 2010

I guess I'd like to see how you're fetching your child data.  Typically (at least how I do it, and how I've seen Rocky's demos), child and parent data are fetched from the database at the same time, with the child data being passed into internal factory methods that load the child records.  Using that methodology, you can check for the existence of any child data before creating any child records.

HTH

- Scott

Jav replied on Monday, August 16, 2010

Scott,

Thanks for you comment. 

I use the same technique for parts of the object graph.  My object graph is rather large with Children, grandchildred and even some great grandchildren.  Besides, many child objects, even an entire branch of 'heredity', may not even exist (legally).  I cannot fetch them at the same time as the root.  I have to load them using foreign keys.  Certainly the entire object graph right now is loaded in a single visit to the server.

Those child objects that are members of a collection are not a problem because I would always create an empty collection anyway.  It is the single child that becomes the issue. 

That is why I have to have a standard, predictable way of handling the situation. 

Jav

tmg4340 replied on Monday, August 16, 2010

Well... others can certainly chime in, but I don't think there's necessarily a "standard" way of managing this type of situation.  It's not one I've had to solve in projects where I've used CSLA before, so I don't have a "predictable" solution.  And ultimately I think "predictable" is more a matter of personal preference - what's predictable to you?  Smile

That said, there certainly are some suggestions I can make.  Most of them relate to the concept of checking that the data exists in the database before doing anything, because that's really the only way of guaranteeing that you don't create your child object.

The most obvious one is the one you already suggested - an Exists check that is run first.  Since this is likely to happen server-side, I don't see a huge performance impact to adding this to your factory methods (or whatever you're using).  It's probably the technique I'd use unless/until I found that it was causing me issues.

If you don't like that option, then depending on the nature of you data, you may be able to augment your initial data load with values that signify whether the data for the optional child(ren) exists.  It's just rolling your exists check(s) into your initial data load, and you can store those flags in internal BO properties.  You'd probably still want those properties to be managed, so that they're serialized and such.  This obviously raises questions of data staleness.  But it's quick, pretty clean, and eliminates the extra DB calls.

Lastly, you could look at something that's often referred to as a "special case object".  It's an object that is essentially used as a placeholder.  It has property values that signify that it's not a meaningful object, and any methods do nothing.  It should be relatively easy to set up your constructor/DP_Create logic to default any new object properties to placeholder values.  Then, if your DB call returns data, all the special data is overwritten.  It's essentially your "invalid object" concept.

I have to say that while I know this is a perfectly valid technique, I am not a big fan of it.  The pattern is admittedly a way to substitute NULL references, and I see where it could have some value here.  But you still have to code for the possibility of getting one of these special-case objects (in your UI, for example), because it's often very difficult to create a totally non-destructive object that still functions like a regular one - and if I have to do that, how much harder is it to code for NULL?  Plus, in order to make sure that calling methods doesn't do anything, you'd likely have to add code to all of them to check and see whether this is a special-case object and essentially no-op the method.  Lastly, since you say that potentially whole hierarchies of your graph don't exist, building special-case objects in that scenario gets a lot harder.

HTH

- Scott

Jav replied on Monday, August 16, 2010

I have started to implement an ExistsCommand : CommandBase<> in each object that may not exist.  Since all these objects are being called from within their parents, I make the call to check if they exist from within the Parent's Fetch method, and only make the call to fetch the child if it exists.  It seems to be doing the trick.

As for having a placeholder, the issue is the opposite.  My UI code fully expects that a given child object may not exist at all.  The problem is the oddball object that actually does come back from the DataPortal_Fetch in such a case.  Its IsNew property is False but its Primary key is zero. If the rest of its fields do not break any rules, you have this oddball lurking in your object graph.  You have to run some code to detect its presence.  Otherwise, if for some reason its IsDirty flag turns true,  it will end up in your DataPortal_Update (Not IsNew) and generate an error (PK = 0).  In other words, it's an uninvited party crasher. 

Jav

Jav replied on Tuesday, August 17, 2010

I suppose another option, in handling an invalid record when DataPortal_Fetch finds none in DB, would be to set the Status = "Deleted".  I am assuming that the FieldManager makes use of this when FieldManager.UpdateChildren() is called.  In DataPortal_DeleteSelf, the Status is set to "Deleted" after the object is removed from the DB - in our case the object already does not exist in DB; and  the id is set to zero - in our case it is already zero.  So my expectation is that if the object graph is Saved again, FieldManager.UpdateChildren() will ignore child objects marked "Deleted".

If the above assumption is correct, then perhaps the boilerplate code in DataPortal_Fetch should be:
                       if (dr.Read())
                        {
                            FromDataReader(dr);
                            using (BypassPropertyChecks)
                            {
                                Status = "Retrieved";
                            }
                            BusinessRules.CheckRules();
                        }
                        else { Status = "Deleted"; }

Jav

Copyright (c) Marimer LLC