CSLA Behaviour with new unchanged entities

CSLA Behaviour with new unchanged entities

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


naskew posted on Thursday, May 15, 2014

Hi,

I was writing some unit tests for code developed within the team and accidentally discovered that creating a new entity and calling save does not actually cause the new entity to be saved but instead returns a still new entity.

I was told that this is the expected behaviour of CSLA, that CSLA only saves an entity once it is dirty and not just because it is new. Is this correct?

Nick

ajj3085 replied on Thursday, May 15, 2014

If your bo is new and dirty, save should end up calling your dataportal insert method.  Save will return a new instance if successful , that is by design as its possible your dpi method throws an exception but some state may have changed leaving your object in a inconsistent state.  since the copy was saved you can still use the original object to let the user continue to interact with it.

skagen00 replied on Thursday, May 15, 2014

Just wanted to add that the return of the new entity is in large part because CSLA revolves around the ability to serialize objects between physical layers.  Once you serialize an object to send it somewhere and deserialize it in another location, it's simply not the same "handle" or object in technical terms.

I only work in a scenario where serialization does occur, but I believe the local data portal doesn't end up serializing/deserializing the object and in this case there is a setting as to whether or not the original object is cloned or not... in the case where it is not cloned with the local data portal, I do believe the original object is the one that would theoretically be saved and even returned as the result of the save.

In general though, if you simply go under the notion of myObject.Save() returning a value containing the saved object, and that you have to use that in your UI context after the save, that's a paradigm you can just follow under all circumstances.

naskew replied on Friday, May 16, 2014

Thanks to the users who responded but I realised that I did not make myself clear in my first post. All our entities follow the same pattern, they have an Id (Guid) which is only assigned when the entity is persisted. All new entities are created by a call to a static method.

var order = Order.NewOrder()

Now order will be marked as IsNew == True and IsDirty == False and Id will be Guid.Empty so calling

var savedOrder = order.Save()

will not actually cause the entity to be Inserted and will return an Order that is still new and still clean and still has no unique Id assigned. Now I realise that one argument might be that without a change in any property, the order cannot contain any information. However behind the entities also share other common information including datemodified, a timestamp (for versioning) and a modifiedby containing the user name of the last inserter/updater. These properties are only filled by the underlying framework that wraps CSLA. So my point of view is that all these other managed properties also contribute to the conceptual state of the entity but  as it stands they do not contribute to the IsDirty property because the values are only set when the Save method results in an insert or update.

I have a fictional but plausible scenario. Suppose that if an order is cancelled we store a cancellation as a child entity. The cancellation only needs to be linked to the order it is cancelling and all the other information is contained in the fact of the existence of the entity. In other words I know when it was cancelled and who cancelled it because that information is in datemodified and modifiedby fields. There is nothing I wish to add. My code for cancelling an order might look like this.

void cancelOrderById(Guid Id)

{

var order = Order.GetById(id);

order.Cancellation = OrderCancellation.NewOrderCancellation();

var updatedOrder = order.Save();

Assert.IsFalse(updatedOrder.Cancellation.IsNew);

}

The assertion will fail because currently when Save is called on the order cancellation it will not be marked dirty and will not save.

It was my hope that Save would always result in an insert if the entity is new even if it is not marked dirty and my question is simply is it right that CSLA requires that a new entity is dirty before it can be saved for the first time?

Sorry for being so verbose, I hope this explains things a little better.

ajj3085 replied on Friday, May 16, 2014

skagen00
I believe the local data portal doesn't end up serializing/deserializing the object and in this case there is a setting as to whether or not the original object is cloned or not... in the case where it is not cloned with the local data portal, I do believe the original object is the one that would theoretically be saved and even returned as the result of the save.

I don't recall when, but at some point this was changed so that the Local dataportal does serialize.  One benefit is that if you do switch on WCF data portal support, you won't suddenly find you're BOs don't serialized; that was the main reason for the change.  Another nice side effect though is that if your DP_I starts changing the BO state and midway something goes wrong, without serialization your object is left in a potentially bad state; the fact that a copy is saved leaves your BO exactly as it was before you called save.

ajj3085 replied on Friday, May 16, 2014

You must have code that creates the new order as not dirty.  Dirty is an indication that your object has changed since it was loaded from the DB. By definition, the normal case is that something that has New is also always dirty.  I'm not sure why you'd want a new order to NOT be dirty.

As far as order cancellation goes, I think your suggested design could be flawed; what reason would you have to not be able to save an OrderCancelation independently of an order?  Certain the cancellation BO can reference an order; perhaps your code would be vary cancellation = OrderCancelation.Cancel(order) and then the cancellation BO can keep the id of the order as one if its properties (much like an FK), but it should be savable on its own I'd think.

And you could still have the OrderCancelation property on the Order for convince if its needed; the getter would just be return OrderCancelation.Get(this). 

Also, if you really did want a new Order to exist in the database, you COULD insert the data you want in your DataPortal_Create method.  That might be unusual, but if its what your use case demands you'll get the behavior you're after.

naskew replied on Friday, May 16, 2014

Andy

You must have code that creates the new order as not dirty.  Dirty is an indication that your object has changed since it was loaded from the DB. By definition, the normal case is that something that has New is also always dirty.  I'm not sure why you'd want a new order to NOT be dirty.

Andy, I think you have hit the nail on the head. The code that generates new instances does so with the IsDirty set to False. This never made any sense to me but clearly if the default Save in CSLA only saves dirty objects and then uses IsNew to decide between insert and update then suddenly everything falls into place. Is this how others feel new instances should be created?

I'll take a look at the code that is used to create new entities. Most of our entity code is generated based on XML descriptions of the model but the code for creating a new instance is within a common base class that wraps CSLA base classes.

Thanks for your help. Being new around here am I expected to indicate that I accept your answer?

JonnyBee replied on Friday, May 16, 2014

Hi,

You could simply calll MarkDirty on the object when it returns to the client.

The default behavior is that a new object is not dirty until a user has modified one ov the properties. 

naskew replied on Saturday, May 17, 2014

JonnyBee

Hi,

You could simply calll MarkDirty on the object when it returns to the client.

The default behavior is that a new object is not dirty until a user has modified one ov the properties. 

Hi Jonny,

I've taken a look in the generated code for the classes and it seems that after initialising a new instance the code deliberately marks the instance as clean with a call to MarkClean(). I'll have a chat with the developers next week because currently they seem to be saying that the problem lies in CSLA when I think it is clear this is not the case.

Nick

Copyright (c) Marimer LLC