This thread looks to be a little on the old side and therefore may no longer be relevant. Please see if there is a newer thread on the subject and ensure you're using the most recent build of any software if your question regards a particular product.
This thread has been locked and is no longer accepting new posts, if you have a question regarding this topic please email us at support@mindscape.co.nz
|
Hi, Does anyone think I would come across any problems if I make a memberwise clone of an Entity? I intend to support some basic change tracking on some of my model objects by keeping the old version of an Entity in the database and referencing it from a newer entity. My current plan is to read an object from the database, create a clone, change one property on the clone and create a relationship to the current (soon to be previous) instance of the object. This is what I'm thinking so far: public TextItem getUpdatedTextItem(string value) Then in the calling code I would call UoW.Add(returnedInstance); (assuming a non-null return value). I guess there might be a need to change properties such as EntityState? I'm using GUID identities in case that's relevant. Related question: Is there a completely different way to approach this such as reacting to an onSaving() LightSpeed event? I worry that adding new Entities to the UoW in the OnSaving event would be too late but please correct me if I'm wrong. Thanks, Chris |
|
|
I think you might well come across problems. You might be safe if you detached the original instance from its UOW before adding the clone, but with the code as shown I think you would end up with two entities of the same type with the same ID in the same unit of work. Or, rather, you wouldn't: you'd probably end up with an exception in the Add method saying that the entity has already been added. Actually, you might get all sorts of strange results since the memberwise clone would already think it was part of the same UOW, because its private reference to the UOW would have been cloned; so adding it might not work (because it would go "oh, I'm already in that UOW, so this is a no-op, no need to add an identity map entry"). (Note that detaching is different from removing: the former deregisters the entity from the identity map, the latter marks the entity for deletion. Also watch out because I think Detach is available only via the UnitOfWork class, not the IUnitOfWork interface.) I would also watch out for associations. A memberwise clone would copy IDs, EntityHolder instances and EntityCollection references. It is not clear to me how valid those references would be. Also since references are bidirectional I think the associated entities would continue to refer to the original instance, not the cloned instance. I don't know what the impact of this would be but it would definitely be something to test during prototyping. You will also have issues with primary keys (this ties into the EntityState concern you raised). You are cloning the ID, but because this is a new/added entity, LightSpeed is going to try to save it as an INSERT rather than an UPDATE. This will make the unique constraint very unhappy. Though actually maybe this will work -- since the Default state is getting cloned, the change will make the clone Modified rather than New. So you might be lucky. But if LightSpeed does do an UPDATE rather than an INSERT, then it will overwrite the existing values in the database, whereas I think you wanted to keep the existing database record and insert a new row. Adding new entities to the UOW in OnSaving is not advisable. You might get lucky, you might not: by the time we call OnSaving, LightSpeed is already walking the changeset, so whether a new entity would get picked up would depend on whether LightSpeed had already walked past that entity's place in the changeset (I think -- I'm not deeply familiar with that part of the code). There's more detailed discussion of this at http://www.mindscape.co.nz/forums/Thread.aspx?PostID=4046. One alternative you could consider is OnPropertyChanged. This would be a safe time to add new entities. You still have the problem of capturing the old values if this is what you need, though. However I would suggest that adding new entities may not be the way to go. I'm really concerned about the identity issue: either you keep the same ID and overwrite the existing record (which seems to negate the point), or you create a new ID and insert a new record (which involves updating all FKs that pointed to the old record, and somehow excluding the old record from all searches), or you assign a new ID to the old version and insert the clone using the old ID (which I suspect will interact fascinatingly with FK constraints, and still leaves you with multiple versions to be excluded from searches). You may have already thought about this stuff and have solutions -- I guess you could do it with CRUD stored procedures -- but it all sounds a bit scary to me. Might it not be better to tackle this in a different way, say by writing audit records to a separate table and capturing the change history that way? Just something to consider. |
|
|
Thanks for the very useful information and advice Ivan. We have decided that the complexity required to make something like this work reliably is just not worth the time we'd have to invest so we're reducing the scope of our plans and just addressing one specific auditing need by writing a little bit of code to manually manage an "old version" flag on the Entity. It's a shame, but I think this is one of those cases where a simple modelling construct at the object level is going to bring up far too many complications when it's actually put to use and mapped to a relational schema. Thanks again, Chris |
|