Copy and Clone objects

Posts   
 
    
Gareth
User
Posts: 24
Joined: 09-Apr-2004
# Posted on: 04-May-2004 00:23:29   

Hi,

Did do a search in the forums but did find anything substantial on copy and cloing entities. I'm a bit new to the OO world and .Net really, so please forgive me if I'm being stupid simple_smile

How to I clone or make a new copy of an entity?

Thanks,

Gareth

Devildog74
User
Posts: 719
Joined: 04-Feb-2004
# Posted on: 04-May-2004 02:51:55   

Typically you can only clone objects that implement ICloneable, and Copy is usually provided by a particular objects implementation.

Entities are not data tables, lists, arrays, etc., they are classes that derive from EntityBase. EntityBase implements these interfaces, IEntity: IEntityCore, IEditableObject, ITransactionalElement, ISerializable, none of which have copy or clone methods (atleast exposed publicly).

In any case, why can't you do this:

Dim customer1, customer2 as CustomerEntity customer1 = new CustomerEntity("CHOPS") customer2 = customer1

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 04-May-2004 09:55:13   

Thanks DevilDog for your explanation, however there is a way to clone an entity simple_smile

An entity class is a container for the Fields object. So if I do this: CustomerEntity customer1 = new CustomerEntity("CHOPS"); CustomerEntity customer2 = new CustomerEntity(); customer2.Fields = customer1.Fields;

then customer2 points to the same fields, and contains the same data.

The EntityFields class and the EntityFields2 class have a 'Clone()' method, which will create a deep copy of the instance and its fields. So you can do this:

customer2.Fields = customer1.Fields.Clone();

I must say, it's not that common to clone an entity in memory, but in rare cases it might be more efficient than a roundtrip to the db.

Frans Bouma | Lead developer LLBLGen Pro
Devildog74
User
Posts: 719
Joined: 04-Feb-2004
# Posted on: 04-May-2004 10:54:50   

What would the difference be between your code and mine?

Wouldnt we both end up with 2 seperate objects that have the same values initially, but can be changed independently from one another?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 04-May-2004 11:24:21   

Devildog74 wrote:

What would the difference be between your code and mine?

Wouldnt we both end up with 2 seperate objects that have the same values initially, but can be changed independently from one another?

No, your code simply creates two variables which reference the same object in memory. So if I do: customer1.CompanyName = "Foo" then customer2.CompanyName is also changed in "Foo" as it points to the same physical object in memory.

This is also the difference between a deep copy and a shallow copy: the first copies every bit of data into a physical different object, the second simply copies the referencing object but not the referenced object. simple_smile

See an object variable, which customer1 and customer2 are, as pointers to a block of memory. When you do: customer1 = new CustomerEntity(), a new block of memory is allocated, filled in and the address is assigned to customer1 as the value.

So when you do customer1.CompanyName, you are in fact looking up the piece of memory reserved for CompanyName in the block of memory customer1 points to. When I do customer2=customer1, the address customer1 points to is now also the address customer2 points to.

This is different with value types, like ints, or structs. When you then do this Dim i, j as Integer i=10 j=i

you'll see that j gets the same VALUE as i, 10. This is because i is a value type, i.e. it doesn't point to a block of memory, it IS the block of memory, the value.

Frans Bouma | Lead developer LLBLGen Pro
Devildog74
User
Posts: 719
Joined: 04-Feb-2004
# Posted on: 04-May-2004 12:21:20   

So, by saying:

dim customer1 as new CustomerEntity() dim customer2 as new CustomerEntity()

There is now room in memory, in 2 different places for an object of type customerEntity.

When you declare the variables as above and enter:

customer2 = customer1, does that perform a shallow copy or, at this point, is customer2 simply a pointer to the same memory address for customer1?

Thanks again for the info.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 04-May-2004 12:52:00   

Devildog74 wrote:

So, by saying: dim customer1 as new CustomerEntity() dim customer2 as new CustomerEntity() There is now room in memory, in 2 different places for an object of type customerEntity.

Correct. simple_smile

When you declare the variables as above and enter: customer2 = customer1, does that perform a shallow copy or, at this point, is customer2 simply a pointer to the same memory address for customer1?

customer2 will then point to the same memory address as customer1 does, the object customer2 pointed to is then 'orphaned' and will be garbage collected.

Frans Bouma | Lead developer LLBLGen Pro
Gareth
User
Posts: 24
Joined: 09-Apr-2004
# Posted on: 04-May-2004 13:28:55   

An entity class is a container for the Fields object. So if I do this: CustomerEntity customer1 = new CustomerEntity("CHOPS"); CustomerEntity customer2 = new CustomerEntity(); customer2.Fields = customer1.Fields;

then customer2 points to the same fields, and contains the same data.

The EntityFields class and the EntityFields2 class have a 'Clone()' method, which will create a deep copy of the instance and its fields. So you can do this:

customer2.Fields = customer1.Fields.Clone();

After a few hours of looking through my classes (before you replied) I could not find a Clone method, I am self servicing. Does this make a difference?

I must say, it's not that common to clone an entity in memory, but in rare cases it might be more efficient than a roundtrip to the db.

And I came to the same conclusion, as I need to change some of the field values anyway, thanks.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 04-May-2004 13:34:37   

Gareth wrote:

An entity class is a container for the Fields object. So if I do this: CustomerEntity customer1 = new CustomerEntity("CHOPS"); CustomerEntity customer2 = new CustomerEntity(); customer2.Fields = customer1.Fields;

then customer2 points to the same fields, and contains the same data.

The EntityFields class and the EntityFields2 class have a 'Clone()' method, which will create a deep copy of the instance and its fields. So you can do this:

customer2.Fields = customer1.Fields.Clone();

After a few hours of looking through my classes (before you replied) I could not find a Clone method, I am self servicing. Does this make a difference?

The method is implemented in the ORMSupport classes, in the EntityFields class. An entity derives from EntityBase which exposes an instance of EntityFields by its Fields property. So every entity has a Fields property and the object exposed by the Fields property does have a Clone method.

Frans Bouma | Lead developer LLBLGen Pro
Posts: 24
Joined: 11-Feb-2004
# Posted on: 21-May-2004 00:41:57   

Otis wrote:

The method is implemented in the ORMSupport classes, in the EntityFields class. An entity derives from EntityBase which exposes an instance of EntityFields by its Fields property. So every entity has a Fields property and the object exposed by the Fields property does have a Clone method.

Even when using the EntityFields clone method I ended up modifying the original entity and not creating a new one.

What I did get to work (with some help from another post) was this:


Customer.IsNew = true;      

for (int i=0; i < Customer.Fields.Count; i++)
{
     Customer.Fields[i].IsChanged = !Customer.Fields[i].IsNull;
}

This creates a new Customer with the values of the original. If there are related records (e.g. Orders), I need to loop through each of those marking the entity as new and setting each field's IsChangedValue. This is not a big deal, it should be easy to handle this with a generic recursive/iterative process. What I am wonder is if this is a recommended way to create a duplicate record, or am I missing the point.

Thanks!

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 21-May-2004 10:35:27   

If you go through that much trouble, it's perhaps ok to simply refetch the entity in another object.

THe clone method should copy the field objects, however it doesnt' copy the referenced related objects, like 'Orders' in 'Customer'

Frans Bouma | Lead developer LLBLGen Pro
Posts: 1
Joined: 07-Aug-2017
# Posted on: 07-Aug-2017 03:14:42   

My Solution for this question, where I was able to clone the child fields was this:

Using C#:

var sourceEntity = new OrderEntity("X");
var cloned = new OrderEntity { Fields = sourceEntity.Fields.Clone() };
cloned.Products.AddRange(sourceEntity.Products.Select(product => new ProductEntity { Fields = product.Fields.Clone() }));

Must do it for each child properties

Otis wrote:

If you go through that much trouble, it's perhaps ok to simply refetch the entity in another object.

THe clone method should copy the field objects, however it doesnt' copy the referenced related objects, like 'Orders' in 'Customer'