Pass Editable Child Collection to another object

Pass Editable Child Collection to another object

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


superkuton posted on Monday, April 05, 2010

How do you pass an Editable Child Collection (ECC) to another object (ERO)?

The ECC shall also become ECC of the new ERO.

 

Its something like this:

Based on a Purchase Request details, prepare the Purchase Order details.

ajj3085 replied on Monday, April 05, 2010

You can do this, but it isn't really a supported scenario.  A child object should have one and only one parent (root) for its entire lifetime.

You can do what you want, there is a thread that tells you how if you search, but you're probably better off cloning the child collection to get the items into the other root object. 

superkuton replied on Monday, April 05, 2010

thanks. how do i clone the child collection to the other object?

ajj3085 replied on Monday, April 05, 2010

Csla provides a Clone method.  You may need to override it to reset database key fields, if you have any and clear the lists DeletedItems collection.

Something like this:

var cloned = myRoot1.Children.Clone(); // may need to override as noted above

myRoot2.Children = cloned;

Although as I said this would be odd... normally you don't have public setters for your child collection property, and alternately you could loop through the root1's children, clone and add to root2's collection.

superkuton replied on Monday, April 05, 2010

thanks again, andy.

Can you point me to some practical sample codes? (I am new to using csla.)

I simply want to copy the items from the 'Puchase Request'(PR) to the new ERO 'Purchase Order' (PO) so that users will no longer need to manually select the items from the PR to the PO.

Will I pass the cloned or copied ERO or ECC to the new ERO in the factory method? or pass the ECC in the UI of the new ERO?

Thanks.

RockfordLhotka replied on Monday, April 05, 2010

There was a whole thread on this topic perhaps 3-4 weeks ago.

The thing to remember is that if you remove an item from a BLB, it is moved into the DeletedList, and when you save that BLB the data will be deleted from the database (or at least your data access layer will be asked to delete it).

So "moving" a child item from one list to another is a little tricky, because you probably don't want the original list to delete the item when it is saved. Or maybe you do. But you need to decide, and code accordingly.

It really is far simpler to clone the child and add it to the other collection. But if you don't want the original collection to delete the item you removed, you'll need to do a little extra work to create a CompletelyRemove() method that not only removes the child, but also removes it from the DeletedList.

superkuton replied on Monday, April 05, 2010

Thanks, Rocky.

I will not be "moving," or "deleting" the child collection from its ERO. I simply wanted to COPY the children to another NEW ERO.

It's somthing like this:

I have a PurchaseRequest_ERO, which has PurchaseRequestDetails_ECC.

Based on the Purchase Request (PR), the user will prepare the Purchase Order (PO) . The Purchase Request ITEMS may not be exactly the same as that of the Purchase Request, but the Purchase Request should serve as the starting point of data entry.

So, we have the PurchaseOrder_ERO, which has the PurchaseOrderDetails_ECC.

How will I create a NEW PurchaseOrder_ERO,  which has PurchaseOrderDetails_ECC copied from the PurchaseRequestDetails_ECC?

For example,

 

PR_ERO

------------

ID                      :  1

Date                 :  1/1/2010

Requisitioner :  My Name

PRDetails_ECC

-----------------------------

ID     |     PR_EROID     |     Item    

1                       1                      Expert C# 2008 Business Objects

2                       2                      Expert VB 2008 Business Objects

 

 

After creating the PR, the user will now create the PO. The output should be something like:

 

PO_ERO

------------

ID                      :  1

Date                 :  1/1/2010

PRID                :  1

Supplier          :  Apress

PODetails_ECC

-----------------------------

ID     |     PR_EROID     |     Item                                                                 |     Cost

1                       1                      Expert C# 2008 Business Objects                    n2

2                       2                      Expert VB 2008 Business Objects                     n2

 

Will cloning do the trick? Or is there a better technique to simply COPY the children of the PR_ERO to the children of the PO_ERO?

Thank you.

ajj3085 replied on Tuesday, April 06, 2010

If you want a new object (which likely means a new row in your database), you may want to consider adding a factory method in your child BO type which simply Creates a new instance using values from another instance of the same type.  Something like:

var newChild = MyChildBO.Create( child );

You would also have a DataPortal_Create( MyChildBO childToCopy ) ;

Does that make sense?

JoeFallon1 replied on Wednesday, April 07, 2010

I had this exact problem with creating a PO from a PO request. I also have to create it from a previous PO, a catalog, a PO on Hold, etc.

In general I solved it like this:

The PO business object has a method:
  Public Sub CreateFromReq(ByVal reqnumber As String, ByVal vendno As String, ByVal shipcode As String)

Inside this method you use the reqnumber to retrieve a complete Req BO from the database.
Then you create a new PO business object which is essentially empty.
Then you call a method to fill the header of the PO with the header data from the Req (you pass the ReqHdr as a parameter to it.)
This is simply a field to field mapping from Source to Destination BO. You could use the DataMapper here if you wanted to.

One side issue is that sometimes I do not want to map every single value. Or I may want to set some other values based on the req value. So it isn't always as clean as you might wish depending on your application logic.

To solve the child detail list issue you continue running code in the method above after setting the header values.

You create a For loop over the list of Req details like this:  (lnCount starts at 0 and increments each time you add a line - not shown in snippet below!)

For i As Integer = 0 To POSource.Reqhdr.Reqlns.Count - 1
  mSourceLine = POSource.Reqhdr.Reqlns.Item(i)
 
mNewLine = poHeader.Polns.AddChild(lnCnt)
  SetPolnData(mSourceLine, mNewLine, POSource.Reqnumber)
Next

The SetPolnData method again matches up fields in the Req object with fields in the PO object. If it is a clean match then DataMapper could work nicely. I have some extra logic in my case so I just matched up the fields I wanted to match and omitted those that I did not want to take from the Req and set my own values.

e.g.
newLine.Itemno = sourceLn.Itemno
newLine.Descr1 = sourceLn.Descr1
newLine.Uom = sourceLn.Uom

And if you have Split Lines for your Req then you set up the same kind of loop inside the SetPolnData method to create each split record.

HTH
Joe

 

superkuton replied on Thursday, April 08, 2010

Thanks, Joe.

The idea is finally settling down on me. My temporary solution then was looping through the detail  items in the UI but your technique is better. I'll be finally posting my solution when I finish up my testing.

 

Thank you, andy, rocky and joe!

Copyright (c) Marimer LLC