My Own Property in Partial Class

Posts   
 
    
bert
User
Posts: 42
Joined: 05-Jun-2005
# Posted on: 18-Jan-2006 08:42:16   

Hi,

I've been trying to use a partial class to extend one of my entities over remoting. In my naivity I thought I could just add the extension and the property as follows and it would be serialized with the other entity fields as the whole class is marked as serialized.

Well, it doesn't work. The entity has the proper values on the client side but when I pick it up on the server side it's initialised to 0 again. I guess it has to do with the custom serialization that LLBLGen employs but I don't know what to do to achieve what I want.

Any help would be appreciated.

 public partial class MyEntity
    {
        private int myProp;
        public int MyProperty
        {
            get
            {
                return myProp;
            }
            set
            {
                myProp = value;
            }
        }
    }

Thanks Bert

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 18-Jan-2006 14:34:27   

The Entity Classes are serializables, and for that they implement ISerializable. So a function called GetObjectData() is used to serialize the members. If you go to your YouEntityClass.cs/vb you will find the override of this function.

And there are a user code region :

// __LLBLGENPRO_USER_CODE_REGION_START GetObjectInfo
// __LLBLGENPRO_USER_CODE_REGION_END

inside which you should write your own custome properties serialization.

If you depend on partial classes you may have this override in your partial class in order to have all the related custom code together.

bert
User
Posts: 42
Joined: 05-Jun-2005
# Posted on: 19-Jan-2006 02:20:32   

Thanks Walaa,

That's what I suspected and did exactly that and now it works fine. I actually put a method call to add the required serialization in the user code region. Then in my partial class I did what was required. This is probably the least intrusive way of doing it and if I understand it right what you put in the user code region will be preserved if you regenerate the classes provided you don't tell the code generator to override everything.

Not sure if you can put the override in the partial class as a new one would be generated in the main class if you regenerate and then it wouldn;t compile. Unfortualtely you can't have partial methods. Maybe I'm worng here?

Bert

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 19-Jan-2006 07:00:52   

What you put in a user code region will always be preserved.

Yeah you are right about the method thing, and I haven't heard about partial meathods before.

Glad that everything works for you.

Posts: 1268
Joined: 10-Mar-2006
# Posted on: 25-Oct-2006 07:35:10   

Waking this thread out of its sleep....

Same issue as above, self servicing, 2 class scenario.

No problem, I can override GetObjectData. That will put the data in to be serialized.

The problem comes in deserialization. In this case, I need code to go into the constructor that takes (Serialization info, StreamingContext context).

Problem is that constructor is generated into the entity class, without a user code region.

End up having to add a method call for a new virtual method SetObjectData into the user region of the base class serialization constructor. Then add this method at the bottom in the custom entity code region.

Finally, override this method in the actual entity.

1) Would it be possible to make a SetObjectData part of the class, much like GetObjectData. This would make this very simple.

2) All the constructors are generated into the actual EntityClass. However, you cannot modify any of them - because you cannot redefine the method and they will be overwritten next generation. I think it would be good to add user code regions to all of these constructors - so they could be modified.

Thoughts on suggestions?

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 25-Oct-2006 09:40:30   

Please don't hijack other/old threads as stated here: http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=7725

Please start a new one.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 25-Oct-2006 10:01:15   

I have a region in my constructor?


/// <summary>Protected CTor for deserialization</summary>
/// <param name="info"></param>
/// <param name="context"></param>
protected CustomerEntityBase(SerializationInfo info, StreamingContext context) : base(info, context)
{
    _customerCustomerDemo = (Northwind.SelfServicing.CollectionClasses.CustomerCustomerDemoCollection)info.GetValue("_customerCustomerDemo", typeof(Northwind.SelfServicing.CollectionClasses.CustomerCustomerDemoCollection));
    _alwaysFetchCustomerCustomerDemo = info.GetBoolean("_alwaysFetchCustomerCustomerDemo");
    _alreadyFetchedCustomerCustomerDemo = info.GetBoolean("_alreadyFetchedCustomerCustomerDemo");
    _orders = (Northwind.SelfServicing.CollectionClasses.OrderCollection)info.GetValue("_orders", typeof(Northwind.SelfServicing.CollectionClasses.OrderCollection));
    _alwaysFetchOrders = info.GetBoolean("_alwaysFetchOrders");
    _alreadyFetchedOrders = info.GetBoolean("_alreadyFetchedOrders");
    _employees = (Northwind.SelfServicing.CollectionClasses.EmployeeCollection)info.GetValue("_employees", typeof(Northwind.SelfServicing.CollectionClasses.EmployeeCollection));
    _alwaysFetchEmployees = info.GetBoolean("_alwaysFetchEmployees");
    _alreadyFetchedEmployees = info.GetBoolean("_alreadyFetchedEmployees");
    _shippers = (Northwind.SelfServicing.CollectionClasses.ShipperCollection)info.GetValue("_shippers", typeof(Northwind.SelfServicing.CollectionClasses.ShipperCollection));
    _alwaysFetchShippers = info.GetBoolean("_alwaysFetchShippers");
    _alreadyFetchedShippers = info.GetBoolean("_alreadyFetchedShippers");


    base.FixupDeserialization(FieldInfoProviderSingleton.GetInstance(), PersistenceInfoProviderSingleton.GetInstance());
    
    // __LLBLGENPRO_USER_CODE_REGION_START DeserializationConstructor
    // __LLBLGENPRO_USER_CODE_REGION_END
}

The problem with a method in the deserialization constructor is that it's not certain all objects are populated at that time. I'll add the method to the todolist though.

Frans Bouma | Lead developer LLBLGen Pro
Posts: 1268
Joined: 10-Mar-2006
# Posted on: 30-Oct-2006 02:25:08   

Sorry - will not hijack anymore.

Otis - I am referring to the derrived class - the Entity class, not the EntityBase class. That one does have that region - and that is what I used to generate my modification above.

I was thinking there should be a region in the Entity class, as I try not to modify the EntityBase class.

In the end, I just need a good (better) way to serialize additional properties.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 30-Oct-2006 10:27:09   

You know... it was already solved, but some internal change made this not working anymore. flushed

The thing is this: The method OnDeserialized is implemented, it's protected virtual and overridable for you, precisely for the purpose you want. Though, it's now never called. The reason is that it was called from FixupDeserialization, however that routine was later on cleared up as it was no longer needed. This effectively orphaned OnDeserialized. This thus wasn't noticed. It wasn't called from the template, which was a mistake.

The thing can be 'solved' in two ways: (not really solved, see below). - by calling OnDeserialized from the template or - by calling OnDeserialized from the FixupDeserialization() routine.

I think it's 'best 'to do the first, as the latter is called in every deserialization constructor. (the Fixup routine is now empty btw).

The problem though is that this routine is a little problematic: the routine should only be called once, and worse: from the leaf of the hierarchy. Though in every class there's a deserialization constructor to deserialize the parts of that class.

This means that if the OnDeserialized routine is called from the deserialization constructor, it will deserialize potentially the members of a class which deserialization constructor hasn't run yet which could lead to problems as data which is assumed to be there isn't there yet.

In theory this could be done in code generation, testing to see if a type is a subtype and a leaf and if so, emit the call. The problem is that if an inheritance hierarchy changes (subtype gets a subtype), the code of the developer could lead to hard-to-trackdown issues at runtime, if the override of OnDeserialized of the subtype is now again overriden for the new subclass.

Say you have Employee <- Manager <- Boardmember.

The deserialization constructor of Boardmember first calls the deserialization constructor of MAnager which calls first the deserialization constructor of Employee. If in the deserialization constructor of Employee a call to OnDeserialized is done, and it's overriden in Boardmember, the method cant assume the deserialization constructor of boardmember has ran as it hasn't. So the best way is to have private methods called at the end of each deserialization constructor routine. However that's only possible if the call is added to a region instead of a protected method which is called always and which is overriden if required.

If I add a region to the derived entity class, it would be best. Then, you're free to either call OnDeserialized() or call your private routine.

(edit) the regions are added, so in the next build these regions are present in the generated code: derived entity, 2-class scenario selfservicing, deserialization constructor.

Frans Bouma | Lead developer LLBLGen Pro
Posts: 1268
Joined: 10-Mar-2006
# Posted on: 31-Oct-2006 02:32:16   

I think that will work nicely. Thanks again - great support.