Deep copy to class that inheirits from an entity

Posts   
 
    
paulwhit
User
Posts: 25
Joined: 21-Oct-2005
# Posted on: 06-Dec-2005 17:14:06   

I have a class that inherits from an entity (CustomerEntityEx). I would like to copy all of the fields including child collections from an existing CustomerEntity. How do I do this?

Thanks! Paul Whitaker

Paul.Lewis
User
Posts: 147
Joined: 22-Aug-2005
# Posted on: 07-Dec-2005 04:35:01   

paulwhit wrote:

I have a class that inherits from an entity (CustomerEntityEx). I would like to copy all of the fields including child collections from an existing CustomerEntity. How do I do this?

Thanks! Paul Whitaker

Paul,

Here are several links that will help you clone your entities. They might even save you some trouble with potential gotcha's.

http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=3938 http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=2580 http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=741

There are many more threads in the forum if you need more information. You didn't mention which version of LLBLGen your running so the provided threads may/may not apply directly to your solution. They will get you down the path.

paulwhit
User
Posts: 25
Joined: 21-Oct-2005
# Posted on: 22-Dec-2005 15:50:13   

I am using the VS2005 C# template and the adapter scenario.

I've tried several different methods and still am having trouble. What I really want to do is set

InventoryRankedItem item = (InventoryRankedItem) inventoryEntity;

but this is not allowed by the compiler.

Here is the scenario (also please read my comments in code):


    public class InventoryRankedItem : InventoryEntity
    {
        public InventoryRankedItem(InventoryEntity row)
        {
            // Do a deep copy

            MemoryStream stream = new MemoryStream();
            BinaryFormatter formatter = new BinaryFormatter();

            formatter.Serialize(stream, row);
            stream.Seek(0, SeekOrigin.Begin);

            // Now what do I deserialize to? base and this are read only
            //???? = (InventoryEntity) formatter.Deserialize(stream);

            // XML serialize works but is far too slow
            //string xml = string.Empty;
            //row.WriteXml(out xml);
            //base.ReadXml(xml);
        }

        private int fieldMatchCount = 0;

        public int FieldMatchCount
        {
            get
            {
                return this.fieldMatchCount;
            }

            set
            {
                this.fieldMatchCount = value;
            }
        }

As you can see I want to add a temporary property to an InventoryEntity for the purposes of ranking them. I need each of the properties in InventoryEntity (whatever they may be) available on the root level for binding purposes, so implementing a "has-a" relationship would require me to expose all of InventoryEntity's properties as InventoryRankedItem properties, and I'm trying to avoid this extra step.

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 23-Dec-2005 07:17:33   

From an OO point of view in order not to make the compiler angry you could do the following:

InventoryEntity item = new InventoryRankedItem();
item = inventoryEntity;

BaseClass item = new DerivedClass();
item = baseItem;

But this will be a shallow copy as discussed here: http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=741

To deserilaize a stream:

InventoryEntity item = new InventoryRankedItem();
item = (InventoryEntity) formatter.Deserialize(stream); 

But for simplicty if your goal is:

to add a temporary property to an InventoryEntity for the purposes of ranking them

you may add this property as a custom property in the generated InventoryEntity class.

look for "#region Custom Entity code" inside the class. And please refer to "Using the generated code - Adding your own code to the generated classes" insde LLBLGen Pro documentation.

paulwhit
User
Posts: 25
Joined: 21-Oct-2005
# Posted on: 28-Dec-2005 15:38:58   

Thank you for the response, but these techniques do not appear to solve my problem.

If I create an item of type BaseClass, then my object will not recognize the properties I'm trying add in the DerivedClass.

Also, I understand the premise in creating a custom entity property, and understand the process. However I have other scenarios that necessitate temporarily extending an entity with custom properties, and do not want to pollute the base entity with this information.

Furthermore, the deserialization syntax you listed will create the same problem that I stated above--since the item is an InventoryEntity, it does not contain the custom temporary properties that I need.

I will probably adjust fire and make it a has-a relationship instead of an is-a relationship. This will require me to create properties to mirror the base level properties (such as Customer.FirstName, etc), and this seems redundant to me. I really want to be able to say "give me an entity (and its complete graph), and add this on to it for the now". This could be useful in my project for ranked lists, mail merging, and form binding purposes.

Please recall from my previous message that the ReadXml functionality works for me, but is far too slow to be practical. If there were a way to "ReadBinary" on an entity class, this may solve the problem because I could create a new DerivedClass and load the data from the BaseClass in the constructor. Is this impossible to create?

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 29-Dec-2005 06:50:00   

What about the before mentioned thread: http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=741

It explains how to deep copy an entity using its fields clone function.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 29-Dec-2005 11:44:51   

If you want to extend a type without using inheritance in code, an obvious choice is the 'decorator' pattern, which aggregates the real type inside the object and exposes the properties you want to expose. You already use that if I interpret your code correctly, however you shouldn't use deep copy technology, as you want to use the Inventory object through the ranked version, am I right? If you want a readonly InventoryRank object, just expose solely get properties.

Frans Bouma | Lead developer LLBLGen Pro
paulwhit
User
Posts: 25
Joined: 21-Oct-2005
# Posted on: 03-Jan-2006 16:56:19   

Otis wrote:

If you want to extend a type without using inheritance in code, an obvious choice is the 'decorator' pattern, which aggregates the real type inside the object and exposes the properties you want to expose. You already use that if I interpret your code correctly, however you shouldn't use deep copy technology, as you want to use the Inventory object through the ranked version, am I right? If you want a readonly InventoryRank object, just expose solely get properties.

Thanks for the reply. I believe that's what I ended up with (although I didn't know it wink ). I would like to expose all of the data properties automatically at the top level (for data binding purposes)... this way I have to expose get property accessors for each field, which is somewhat annoying but not that big of a deal stuck_out_tongue_winking_eye . This is how I ended up:


public interface IRankedItem
{
int Rank { get; }
}

public class InventoryRankedItem : IRankedItem
{
private entity;
public Entity { get { return this.entity; } set { this.entity = value; } }

public InventoryRankedItem(InventoryEntity entity)
{
this.entity = entity;
}
public int Rank
{
get { ... }
}
public string DisplayName
{
get{ return Entity.DisplayName; }
}
...
}