1:1, Parent, and 1:N DB insertion requirements

1:1, Parent, and 1:N DB insertion requirements

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


snakebyteme posted on Monday, August 29, 2011

As I read the CSLA book, I see that the examples for Insertion of data are generic:

Parent then Children  or Children then Parent.

When dealing with a relational database, this is not always the case.

The correct sequence is:

1:1 Children then Parent then 1:N Children

Otherwise, there will be orphaned 1:1 children written to the database.

To prevent having to explicitly handle each 1:1 child in the portal insert, it would be nice if there was an attribute that could be set on the 1:1 children and then a FieldManager call that would drill through the Properties with that attribute.

FieldManager.Update1to1Children(Me)
AddMe()
FieldManager.Update1toNChildren(Me)

I'm a little behind on CSLA (using 3.8.x). Is something like this already implemented in the current revision?

 

JonnyBee replied on Monday, August 29, 2011

Hi,

First, I'd argue that the correct sequence should be Parent - then 1:1 or 1:N children in a transacted update/insert.  I'd prefer to have the parent create any unique id and pass it on to its children (no matter relationship) and make them know how to save themselves.

Assuming that you have an EditableObject with properties that is either a EditableChild (1:1) or EditableChildList (1:N) , you should still only need to call either FieldManager.UpdateChildren or  DataPortal.UpdateChild for each child object.

FieldManager.UpdateChildren will loop through all child object properties (whether 1:1 or 1:N) and call DataPortal.UpdateChild for each property.

    public void UpdateChildren(params object[] parameters)
    {
      foreach (var item in _fieldData)
      {
        if (item !null)
        {
          object obj = item.Value;
          if (obj is IEditableBusinessObject || obj is IEditableCollection)
            Csla.DataPortal.UpdateChild(obj, parameters);
        }
      }
    }


And Csla.DataPortal.UpdateChild will check for object type and call the appropriate methods for

Meaning that if your child object type is Core.BusinessBase then assume 1:1 else it is a list and 1:N so just call Child_Update on the list and the list object has a default implementation of this method to process the list:

From BusinessListBase:

    protected virtual void Child_Update(params object[] parameters)
    {
      var oldRLCE = this.RaiseListChangedEvents;
      this.RaiseListChangedEvents = false;
      try
      {
        foreach (var child in DeletedList)
          DataPortal.UpdateChild(child, parameters);
        DeletedList.Clear();

        foreach (var child in this)
          if (child.IsDirty) DataPortal.UpdateChild(child, parameters);
      }
      finally
      {
        this.RaiseListChangedEvents = oldRLCE;
      }
    }

As long as these child updates are transacted - why care about sequence (by default)?

If you need a certain sequence then use DataPortal.UpdateChild for those properties that must happend in a certain sequence and call FieldManager.UpdateChildren to process the rest.

snakebyteme replied on Monday, August 29, 2011

If we put your preferences aside:

If the database has an identity column (auto incrementing integer ID), then you must insert 1:1 children first or they will be orphaned if the foreign key is nullable. You will get a foreign key error if it is not nullable.

Generating child IDs would probably require a trip to the database for each child needing a key unless you used a GUID (who wants that?).

Currently, I have to "Insert 1:1 --> Insert Me --> Insert 1:N" in the portal methods which requires explicit calls to the 1:1 children objects to add themselves to the database and then mark themselves as clean to prevent being invoked again by the FieldManager update call.

I was offering a potentially elegant way to handle the generic concept without tons of explicit code in every object's portal methods.

Your proposed solution is to "make it work with additional code per use case", which defeats the purpose.

RockfordLhotka replied on Monday, August 29, 2011

I don't plan on adding ORM-like features to CSLA.

But you can certainly create your own attribute and extension methods for FieldManager to do what you suggest. That would require no changes to CSLA itself, and should meet your needs.

Copyright (c) Marimer LLC