Entity Copy

Posts   
 
    
BeauButton
User
Posts: 5
Joined: 13-Oct-2004
# Posted on: 01-Dec-2004 22:41:02   

Is there an easy way to copy an entity? e.g. I have an entity that has been populated from the database and i'd like to add a new row to the database using the existing entity. If so, is there a way to do it recursively for entities that are fetched with a prefetch path?

Thanks!

Otis avatar
Otis
LLBLGen Pro Team
Posts: 38110
Joined: 17-Aug-2003
# Posted on: 02-Dec-2004 10:55:20   

effectively cloning an entity graph can be done by serializing it to a memorystream, then seek back the memorystream pointer to the beginning and then deserialize the memorystream back into a new entity object (or entity collection if you serialized that).

That will not save to new entities though, you then made a copy of the entities. If you want NEW entities, do the following. (I illustrate it here using myCustomer, which is a customerentity)

myCustomer.IsNew = true; myCustomer.Fields.IsDirty = true; for(int i=0;i<myCustomer.Fields.Count) { myCustomer.Fields[i].IsChanged = true; }

now myCustomer can be saved as a new entity. Be sure to give it a new PK of course if the entities don't have identity/sequenced PK's simple_smile

BSAPD avatar
BSAPD
User
Posts: 42
Joined: 02-Jul-2004
# Posted on: 02-Dec-2004 16:34:06   

Can you post a code sample of your memory stream solution. Also, there are issues with your sample of marking the fields IsChanged property: 1. You cant set IsChanged if the field was NULL because it will try to save DateTime.MinValue if it was a date field and that blows up in SQL Server. 2. You cant set IsChanged on a timestamp column because that will also blow up.

Basically your example dosent work, but this seems to...

MyEntity copy = new MyEntity();

copy.Fields = (IEntityFields2)((EntityFields2)entityToCopy.Fields).Clone();

copy.IsDirty = true;

//Note this will skip the last column which is our timestamp for(int i=0;i<copy.Fields.Count-1;i++) { if(!copy.Fields[i].IsNull && !copy.Fields[i].IsPrimaryKey) { copy.Fields[i].IsChaged = true; } }

Now that this is working we still need to do a deep copy of all the related entities. If you could post an example of your idea that would be great!!! smile

Otis avatar
Otis
LLBLGen Pro Team
Posts: 38110
Joined: 17-Aug-2003
# Posted on: 02-Dec-2004 16:40:50   

OK, thanks for clearing up the details simple_smile

The memory stream trick goes as follows:


// fetch data in myCustomer entity. (a graph). 
// BinaryFormatter is the formatter for remoting, part of .NET
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
formatter.Serialize(stream , myCustomer);
// seek the stream back to the beginning.
stream .Seek(0, SeekOrigin.Begin);

// deserialize the data back into a new instance (and all the related entities)
CustomerEntity clone = (CustomerEntity)formatter.Deserialize(stream);

BSAPD avatar
BSAPD
User
Posts: 42
Joined: 02-Jul-2004
# Posted on: 02-Dec-2004 16:59:15   

OK, that is pretty slick... One question though... Do I now have to recursively go through all the IEntity2 children of the cloned entity and set their fields IsChanged property to true? Also, how do we update the FK's for the children entities since the new PK is not created yet? Will the entities handle this for us?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 38110
Joined: 17-Aug-2003
# Posted on: 02-Dec-2004 17:08:45   

BSAPD wrote:

OK, that is pretty slick... One question though... Do I now have to recursively go through all the IEntity2 children of the cloned entity and set their fields IsChanged property to true?

Yes.

Also, how do we update the FK's for the children entities since the new PK is not created yet? Will the entities handle this for us?

The sync info inside the entities was to the entities in the graph. As these are deserialized into the graph as well, the sync info should point to the correct entities. So if you simply save the entities again, the FK's will be updated automatically.

dion avatar
dion
User
Posts: 11
Joined: 23-Apr-2004
# Posted on: 24-Dec-2004 23:28:47   

Hi, this is the method I use to set all fields of an Entity 'dirty'. Maybe it's of some help to you.

It marks all fields as changed, except the primary-keys and timestamps (DbType 19). Also it resets the fields containing a null value (so you're sure the null is written back to the DB).

private void setEntityDirty(IEntity entity)
{
    entity.IsDirty = true;
    for(int i=0; i<entity.Fields.Count; i++)
    {
        //don't mark the primary-keys and timestamps (DbType 19) as changed
        if(!entity.Fields[i].IsPrimaryKey && entity.Fields[i].SourceColumnDbType != 19)
        {
            entity.Fields[i].IsChanged = true;
            if (entity.Fields[i].IsNull)
            {
                //reset Null fields
                entity.SetNewFieldValue(i, null);
            }
        }
    }
}
ZaneZ
User
Posts: 31
Joined: 21-Dec-2004
# Posted on: 21-Jan-2005 04:18:14   

Has anyone written a utility method that copies an entity and all of its related objects? Or does this type of copy method have to be specific for each type of entity?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 38110
Joined: 17-Aug-2003
# Posted on: 21-Jan-2005 10:42:23   

You can do that by serializing the entity using the binary formatter into a memory stream, then rewind the stream and deserialize teh graph back into a new entity, which will then hold all new objects with the same data. simple_smile

ZaneZ
User
Posts: 31
Joined: 21-Dec-2004
# Posted on: 21-Jan-2005 16:00:09   

Otis wrote:

You can do that by serializing the entity using the binary formatter into a memory stream, then rewind the stream and deserialize teh graph back into a new entity, which will then hold all new objects with the same data. simple_smile

Thanks for the quick response. I've tried that and it does seem to work. I've copied the entity, and used the function in the above post to make each entity "new". However, when I go to save the entity back to the database, it doesn't seem to save the related objects as new entities.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 38110
Joined: 17-Aug-2003
# Posted on: 21-Jan-2005 16:32:43   

You copy the exact state of all the entities, so if you want to change that / need to change that for your further actions, you have to reset their isnew flags as well...

ZaneZ
User
Posts: 31
Joined: 21-Dec-2004
# Posted on: 21-Jan-2005 16:40:02   

I'll try that. Thanks a lot for your help.

wexa
User
Posts: 38
Joined: 27-Jul-2007
# Posted on: 15-Jan-2008 18:31:36   

I tryed the above code but was an error, it worked like that:

SitEntity srcEntity = (SitEntity)gridView1.GetRow(gridView1.FocusedRowHandle);
            adapter.FetchEntity(srcEntity);
            SitEntity destEntity = new SitEntity();

            destEntity.Fields = srcEntity.Fields.Clone();
            destEntity.IsNew=true;
            destEntity.Fields.IsDirty = true;
            for (int i = 0; i < destEntity.Fields.Count;i++ )
            {
                destEntity.Fields[i].IsChanged = true;
            }

I hope this helps

goose avatar
goose
User
Posts: 392
Joined: 06-Aug-2007
# Posted on: 15-Jan-2008 21:08:22   

I thinks this seems like an invalid cast

(SitEntity)gridView1.GetRow(gridView1.FocusedRowHandle)

what error are you getting?

Jazz
User
Posts: 63
Joined: 12-Aug-2005
# Posted on: 10-Feb-2008 17:36:10   

hi there, maybe i got a snippet of code that might help(for adapter though):


public static void SetEntityDirty(IEntity2 entity, bool setNew) {
    entity.IsDirty = true;
    if(setNew) {
        entity.IsNew = true;
    }
    for (int i = 0; i < entity.Fields.Count; i++) {
        //don't mark the primary-keys and timestamps (DbType 19) plus read-only as changed
        if (!entity.Fields[i].IsPrimaryKey && !entity.Fields[i].IsReadOnly) {
            entity.Fields[i].IsChanged = true;
            if (entity.Fields[i].IsNull) {
                //reset Null fields
                entity.SetNewFieldValue(i, null);                               
            }
        }
    }
}

Regards, André

like2175
User
Posts: 83
Joined: 27-Mar-2006
# Posted on: 27-Aug-2008 11:44:29   

Here is my VB version for my VistorEntity as an example for Self-Service . I added this in the ' __LLBLGENPRO_USER_CODE_REGION_START AdditionalInterfaces section of my VisitorEntity Class. Hope it helps.




' __LLBLGENPRO_USER_CODE_REGION_START AdditionalInterfaces 

'''<summary>
    '''Get a copy of an existing VisitorEntity.
    '''</summary>
    Public Function Duplicate() As VisitorEntity

      Me.IsNew = True
      Me.Fields.IsDirty = True
      For i As Integer = 0 To Me.Fields.Count - 1
        Me.Fields(i).IsChanged = True
      Next i

      Return Me

    End Function
    ' __LLBLGENPRO_USER_CODE_REGION_END