Deep cloning

Posts   
 
    
Jazz
User
Posts: 63
Joined: 12-Aug-2005
# Posted on: 13-Aug-2005 21:56:26   

Hello there,

first of all I want to thank you for this great framework. After struggling with DataTable generation for hierarchical data-structure in Intersofts WebGrid I am now very pleased with this O/R Mapping framework.

Anyway, here comes my question:

I got an Entity with another ChildEntityCollection (1:n) and I keep cloning it by cloning the Fields, setting them as changed and the Entities dirty. I clone the ChildEntities using GetMemberEntityCollections on the parent Entity and doing the same with those Fields. After that I apply the related ParentEntity to all ChildEntites using SetRelatedEntity.

When I recursively save the ParentEntity I get an Constraint Error. Because the ParentEntity doesn't have a correct Id yet to be referenced by the ChildEntities.

Do I have to save the ParentEntity first non-recursively to get an appropriate Id? Does the framework not recognize which Entity relies on which and thus saving ParentEntities first to gain referenced Ids? Is there a certain order to keep in mind? And what happens when I save the ChildEntities first using recursive-Save?

Regards, André

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39590
Joined: 17-Aug-2003
# Posted on: 15-Aug-2005 10:45:14   

Jazz wrote:

Hello there,

first of all I want to thank you for this great framework. After struggling with DataTable generation for hierarchical data-structure in Intersofts WebGrid I am now very pleased with this O/R Mapping framework.

smile

Anyway, here comes my question: I got an Entity with another ChildEntityCollection (1:n) and I keep cloning it by cloning the Fields, setting them as changed and the Entities dirty. I clone the ChildEntities using GetMemberEntityCollections on the parent Entity and doing the same with those Fields. After that I apply the related ParentEntity to all ChildEntites using SetRelatedEntity.

When I recursively save the ParentEntity I get an Constraint Error. Because the ParentEntity doesn't have a correct Id yet to be referenced by the ChildEntities.

Hmm. You should use the property mapped onto the relation (like add all clones of Order to clonedCustomer.Orders). Though you can also use the memorystream serialization trick to serialize the complete graph in one go: http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=2580 (for example)

Do I have to save the ParentEntity first non-recursively to get an appropriate Id? Does the framework not recognize which Entity relies on which and thus saving ParentEntities first to gain referenced Ids? Is there a certain order to keep in mind? And what happens when I save the ChildEntities first using recursive-Save?

If the references are setup ok, the entities will signal eachother when saved, and the recursive save code doesn't mind if you start at the bottom, it will find its way through the graph and save it in the right order.

Frans Bouma | Lead developer LLBLGen Pro
Jazz
User
Posts: 63
Joined: 12-Aug-2005
# Posted on: 15-Aug-2005 15:21:46   

Hello Otis,

thanks for your reply. What I didn't write was that I want to write a generalized method that can clone every IEntity derrived class. My approach goes like the following.


public IEntity CloneEntity(IEntity source) {            
    IEntity clone = GeneralEntityFactory.Create(EntityHelper.GetEntityType(source));
    clone.Fields = EntityHelper.CloneFields(source);            
    ArrayList memberEntities = source.GetMemberEntityCollections();
    foreach(EntityCollectionBase coll in memberEntities) {              
        foreach(IEntity subEntity in coll) {                    
            IEntity subClone = GeneralEntityFactory.Create(EntityHelper.GetEntityType(subEntity));
            subClone.Fields = EntityHelper.CloneFields(subEntity);
            clone.SetRelatedEntity(subClone, subClone.GetType().Name.Replace("Entity", ""));            
        }               
    }
    return clone;           
}

from EntityHelper:
public static IEntityFields CloneFields(IEntity srcEntity) {
    IEntityFields fields = (IEntityFields)((EntityFields)srcEntity.Fields).Clone();
    for(int i=0; i<fields.Count; i++) {
        fields[i].IsChanged = true;             
    }
    fields.IsDirty = true;
    return fields;
}

public static EntityType GetEntityType(IEntity entity) {
    EntityType et = new EntityType();
    return (EntityType)EntityType.Parse(et.GetType(), entity.GetType().Name);
}

Please excuse my way of getting the actual name of the entity using getType.Name etc. Maybe you know a better way to go. If I understood it right the serializing approach also needs all fields to be set as changed and entities to IsNew=true.

Regards, André

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39590
Joined: 17-Aug-2003
# Posted on: 16-Aug-2005 11:35:14   

Jazz wrote:

Hello Otis,

thanks for your reply. What I didn't write was that I want to write a generalized method that can clone every IEntity derrived class. My approach goes like the following.


public IEntity CloneEntity(IEntity source) {            
    IEntity clone = GeneralEntityFactory.Create(EntityHelper.GetEntityType(source));
    clone.Fields = EntityHelper.CloneFields(source);            
    ArrayList memberEntities = source.GetMemberEntityCollections();
    foreach(EntityCollectionBase coll in memberEntities) {              
        foreach(IEntity subEntity in coll) {                    
            IEntity subClone = GeneralEntityFactory.Create(EntityHelper.GetEntityType(subEntity));
            subClone.Fields = EntityHelper.CloneFields(subEntity);
            clone.SetRelatedEntity(subClone, subClone.GetType().Name.Replace("Entity", ""));            
        }               
    }
    return clone;           
}

from EntityHelper:
public static IEntityFields CloneFields(IEntity srcEntity) {
    IEntityFields fields = (IEntityFields)((EntityFields)srcEntity.Fields).Clone();
    for(int i=0; i<fields.Count; i++) {
        fields[i].IsChanged = true;             
    }
    fields.IsDirty = true;
    return fields;
}

public static EntityType GetEntityType(IEntity entity) {
    EntityType et = new EntityType();
    return (EntityType)EntityType.Parse(et.GetType(), entity.GetType().Name);
}

Please excuse my way of getting the actual name of the entity using getType.Name etc. Maybe you know a better way to go.

string name = entity.Fields[0].ContainingEntityName; Not really documented, but it contains the name of the entity it's in, like "CustomerEntity" simple_smile

If I understood it right the serializing approach also needs all fields to be set as changed and entities to IsNew=true.

That's indeed true simple_smile

Frans Bouma | Lead developer LLBLGen Pro