How to pass Parent ID to Child for saving to relational database

How to pass Parent ID to Child for saving to relational database

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


cwinkelmann posted on Sunday, March 11, 2012

I have a Parent Root object (PR) as a BusinessBase which will be in a DynamicBindingListBase to automatically save when changes are made in WinForms. 

The PR has a child collection implemented as a BusinessBindingListBase which will contain Child objects that require the PR id from the database in order to relate them correctly to the parent record.

These Child records will also contain a collection of Child records of the same type basically being a recursive type to n-level....

When the parent object is new, I don't want the child collection to AllowNew, so (false)... There is no specific event like IsNew property changed event, so I can only use the Saved event and check as often as that occurs to toggle the AllowNew property.

Any ideas about a well tested method for passing the parent ID to the child objects after it has been saved... ???

 

Thanks greatly for the tips!

Chris

tiago replied on Monday, March 12, 2012

Hi Chris,

Dynamic Root List/Dynamic Root is suited for editing data in a DataGridView. If you have children, I should use Editable Root stereotype and save all the object graph in one single operation . If you really need to save child collections as you go along and will have a master->detail->detail->...->detail scenario, then you should Dynamic Root List / Dynamic Root on each level: each DataGridView will open a detail DataGridView passing the parent ID as a fetch criteria. This is done by the UI layer - no CSLA magic here :)

For a more conventional approach usign Editable Root / Editable Child List / Editable Child you can download and have a look at the DeepLoad sample to see how it's done. This sample fetches a 6 level data structure in a single round trip to the database.

cwinkelmann replied on Monday, March 12, 2012

I regret the documentation on CslaGenFork --- DeepLoad sample is very lacking. There are several implementations in the test but they are is no document indicating the terminology and what events drive the saving of the data in which objects. Now I am pouring over the code to decipher it but I'm not sure this is the most efficient way to learn it. 

http://cslagenfork.codeplex.com/documentation is mostly incomplete and has little information on active links.

On DeepLoad, what is the significance of the ERCLevel and ERLevel? Why are some objects prefixed with A2-12 or B1-12, C2-12, D1-12... ( Is this because they stand for "Editable Root Child" and "Editable Root"? I notice the set with the A1 and C1 missing lack the collection as an object.

So this example indicates how objects are loaded with a single query, but this does not indicate how child objects will save themselves. The child will need to know the Parent's ID unless the Parent is saving the child object. I'm not so comfortable having other objects load and save the child.

Are there any more examples available with more documentation?

 

 

cwinkelmann replied on Monday, March 12, 2012

Mr. Leal,

Just to be clear, I want to thank you for your response! I am not it does not help, I was very much hoping the sample project would have more documentation..

In light of CslaGenFork, I am curious if you would like to see the pattern I've developed for removing tons of code from the BOs for the Data Access Layer. I intend that each object will be smart and know how to insert, update, and delete, as well as load (for refresh when the TimeStamp is off). For performance, the collections will know how to load the child objects because they will be created with the parent having access to the Parent ID. (so they know which records to pass in a criteria object.)

I intend that each object still loads itself from a DTO received from the collection's DAL request. (so no collection cares about the inner workings of a child, only knows what DAL method is required to get the data and then call the DataPortal.FetchChild<childType>(DTO) method...

Perhaps since some collections will be children of other objects, they will have a reference to the Parent. I can get the ParentID from that reference and use it to create new with the AddNewCore() override method. I'll have to make a rule that a child cannot save (is Invalid) if the ParentID is not set.

Geeze, it does seem like there is too much to do while getting my head around this framework... Forgive me for being a little frustrated...

Thanks for your contributions though!!!

JonnyBee replied on Tuesday, March 13, 2012

Hi,

Look at the ProjectTracker sample.

Assuming that you are using DataPortal_XYZ/Child_XYZ methods you should use DataPortal.UpdateChild(ChildObjectOrList) or DataPortal.UpdateChildren() with parameters so that you may pass either the parent object or the ParentId to the children as a parameter.

NOTE - this requires that ALL Child_XYZ methods in an object  have the same signature.

Parent:
DataPortal.UpdateChild(ChildList, myId)

Child:

protected void Child_Insert(long myParentId)
{
       // will always get the parent id as the parameter
}

protected void Child_Update(long myParentId)
{
         // will always get the parent id as the parameter
}

protected void Child_DeleteSelf(long myParentId)
{
         // will always get the parent id as the parameter
}

You may specify zero, one or more parameters on DataPortal.UpdateChild or DataPortal.UpdateChildren. Just be aware that all Child_XYZ methods must match the signature of the parameters. This is typically done in the Insert/Update method of the parent object in the Data Acces to let the parent id's or object cascade down to child objects.

cwinkelmann replied on Tuesday, March 13, 2012

Yes, I am using the DataPortal_XYZ and Child_XYZ methods. I am a little unclear why all the signatures need to be the same. Looking at the ChildDataPortal, it seems it does not use Generics the same way as the DataPortal_XYZ methods. Other than setting the objects as IsChild= true, was there any specific reason not to mirror the flexibility of child methods just like the DataPortal methods?

 

The answer provided is a much closer to what I needed. Since I can pass parameters to the Child_XYZ methods that is the way it must be.

What is the difference then if I use a factory method like 

ChildObject.GetChild(parent)

------

public ChildObject GetChild(ParentObject parent)

{

     ChildObject o = DataPortal.Fetch<ChildObject>(parent);

     o.MarkAsChild();

}

---------

after as MarkAsChild() is protected so it is available to the Child class inheriting from the Core.BusinessBase... Is there anything else I'm missing that the Child_XYZ methods to that is

 

So basically in ChildDataPortal they do one of two options:

        // tell the business object to create its data
        if (hasParameters)
          obj.CallMethod("Child_Create", parameters);
        else
          obj.CallMethod("Child_Create");

In Contrast! the DataPortal_XYZ methods will use reflection to find a more exact method for execution, for example in MethodCaller.cs....    private static System.Reflection.MethodInfo GetMethod(Type objectType, string method, bool hasParameters, params object[] parameters)
    {
      System.Reflection.MethodInfo result = null;

      object[] inParams = null;
      if (!hasParameters)
        inParams = new object[] { };
      else if (parameters == null)
        inParams = new object[] { null };
      else
        inParams = parameters;

      // try to find a strongly typed match

      // first see if there's a matching method
      // where all params match types
      result = FindMethod(objectType, method, GetParameterTypes(hasParameters, inParams));

 

Anyway, I'm curious why the pattern for child methods was not mirrored from the regular DataPortal methods...

Well, I'm still working on this and hope to understand more about the CSLA Framework and more of the why as well as the what...

Thanks for your help!!!

:-)

 

 

JonnyBee replied on Tuesday, March 13, 2012

The main difference is that the "root" DataPortal will:

The Child dataportal call will only

So the Root dataportal call is typically only used on a child that is LazyLoaded - ie: not loaded as a member of the root data access but has it's own DataPortal_Fetch to be called from the client after root object is typically active in databinding.

cwinkelmann replied on Wednesday, March 14, 2012

ok, the last part helps very much.

Basically the Child_XYZ will be called within a process started by a DataPortal_XYZ method where some of the data originally fetched will be passed by DTO or anything to the Child_XYZ method where the child is created and returned...

The Lazy Load properties will not call Child_XYZ methods because that is a new request from perhaps an already databound parent object. It seems then it does not matter if the property is a child by relation (containing the parent id) or if it is just a list of random other properties that do not have to maintain a relationship... Either way, the DataPortal methods are called for lazy load and real child objects then must still have MarkAsChild() method called...

I am close to testing an implementation but I want to see if the requirement of the Child_XYZ methods having the same signature is true. It just seemed the methodCaller was using reflection to find the right method signature on all methods independent of previous calls and would look in cache for a shortcut (performance) first...

Thanks!!!!

cwinkelmann replied on Tuesday, March 13, 2012

Please correct me if I'm wrong, but it appears that both the Child_XYZ and DataPortal_XYZ methods are routed through the MethodCaller class where they cache the method signature and if not found, then they both call

MethodCaller.CallMethod(this.Instance, method, parameters);

which will again use reflection to find the right method.

If this is correct, then I'm not sure it is true that all the method signatures need to be the same and also each XYZ method can have multiple signatures and based on the parameters provided it should identify the correct method to execute...

Thanks again to all the CSLA contributors!

 

 

JonnyBee replied on Tuesday, March 13, 2012

Hi,

MethodCaller will throw an exception if a matching method is not found.
So the method MUST have the correct number of parameters!!!

 

Copyright (c) Marimer LLC