Command and Multiple Root Save

Command and Multiple Root Save

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


asp2go posted on Tuesday, May 11, 2010

We are referring to the Csla Wiki entry (modified example as below) regarding Command Base and multiple root objects as a potential way to handle some of our requirements. What would be the best way to require use of the ShipmentSaver class and for example prevent calling save directly on the Shipment class by a UI developer. We want to allow directly editing and saving Order objects but whenever a Shipment is being saved it should require use of ShipmentSaver to allow for additional updates to be made to the order. This needs to be done inside a single transaction.

Or do you have better suggestions of ways to handle this scenario? Thanks.

 

[Serializable]
public class ShipmentSaver : CommandBase
{
public ShipmentEdit Shipment { get; private set; }
public OrderEdit Order { get; private set; }

public static ShipmentSaver SaveObjects(
ShipmentEdit shipment, OrderEdit order)
{

// will do some additional tasks here to set properties for the order due to it being shipped/partially shipped
SetOrderShipmentData(shipment, order)

var cmd = new ShipmentSaver { Shipment = shipment, Order = order };
cmd = DataPortal.Execute(cmd);
return cmd;
}

[Transactional(TransactionTypes.TransactionScope)]
protected override void DataPortal_Execute()
{
using (var ctx = ConnectionManager.GetManager(...))
{
Shipment = Shipment.Save();
Order = Order.Save();
}
}
}

RockfordLhotka replied on Tuesday, May 11, 2010

You just want to prevent the use of Shipment.Save() except from within the command object?

I'd override Save() and have it throw an invalid operation exception. Then implement an internal SaveFromCommand() method that can be called from your command object - and have it do this

internal Shipment SaveFromCommand()
{
  return base.Save();
}

There are variations on this theme, but this is the basic idea.

rsbaker0 replied on Tuesday, May 11, 2010

We started down the CommandBase route when trying to decide how to save multiple "root" objects together in a transaction, but after some experimentation found it seemed to make more sense to use a BusinessBase derived class.  You don't really even have to write any more code if you don't want to, but you can do things that CommandBase will not easily do (like have business rules, additional properties both managed or otherwise, bindability).

Note that we started with CSLA 2.0 before there was a child data portal and don't use that feature, so (at least in our class library) there seems to be no problem at all with treating root objects as children of other objects. The only place we find this seems to matter is if you want to put "root" objects into a BusinessListBase class, in which case they must be marked as child.

Being able to have rules that validate the group of objects (as well has have other input properties that CSLA will fully manage) seems to make this approach far more flexible.

RockfordLhotka replied on Tuesday, May 11, 2010

That's true - BusinessBase works for this also.

In CSLA 4 CommandBase does support managed backing fields and RegisterProperty(), but it still doesn't have business rules and so forth.

asp2go replied on Wednesday, May 12, 2010

@ Rocky,

It may not be critical but yes was just trying to override the save. Since save is from the base class however it is necessary to have a Shipment return type so can't seem to avoid leaving that open?

 

@rsbaker0,

So are you essentially doing the same process as the Command Base object in the example - Setting each root object as a property and then calling Save inside a transaction or are you suggesting that you do something different than that?

Assuming that the objects still save individually then each root is validating on its own - I assume then that the benefit is that you could set additional validations for 'between object' rules that apply?

 

Thanks for the ideas

rsbaker0 replied on Thursday, May 13, 2010

asp2go

So are you essentially doing the same process as the Command Base object in the example - Setting each root object as a property and then calling Save inside a transaction or are you suggesting that you do something different than that?

Assuming that the objects still save individually then each root is validating on its own - I assume then that the benefit is that you could set additional validations for 'between object' rules that apply?

Yes, this is it exactly. To "save" a CommandBase, you're implementing DataPortal_Execute. To switch to a BusinessBase you just do whatever you were doing in DataPortal_Execute in DataPortal_Update instead and use the same style of transaction management you were using before.

RockfordLhotka replied on Thursday, May 13, 2010

asp2go

@ Rocky,

It may not be critical but yes was just trying to override the save. Since save is from the base class however it is necessary to have a Shipment return type so can't seem to avoid leaving that open?

I'm suggesting that you use a unit of work object (subclass of commandbase or businessbase or even sometimes readonlybase) that operates against a set of several root objects.

My only point about overriding Save() in the root object(s) is that you can do so to prevent normal use of that Save() method - throwing an exception to remind developers that they shouldn't be using Save() on that object.

asp2go replied on Saturday, May 15, 2010

Thanks to both for comments - it seems to be working as desired using this approach.

Copyright (c) Marimer LLC