Problem deserializing inherited entites

Posts   
 
    
takb
User
Posts: 150
Joined: 12-Mar-2004
# Posted on: 18-Sep-2006 15:30:28   

We have some code that depends on the correct setting of the IsChanged flag on Primary Key fields. We create entities on the presentation layer and they are passed via remoting to the service layer for processing. We are seeing a behavioural difference between entities participating in an inheritance hierarchy and entities not participating in an inheritance hierarchy.

Scenario 1: create a “normal” entity (not participating in an inheritance hierarchy) and set some fields but DON’T TOUCH the (non-identity) PK field then pass it to the service layer (thus it is serialized and deserialized). On the service layer the PK of the entity has IsChanged==false

Scenario 2: create an entity which is a subclass of another entity, set some fields but DON’T TOUCH the (non-identity) PK field (inherited from base) nor the FK to the PK. Then pass it to the Service layer. On the service layer, the PK of the base entity has IsChanged==true

Scenario 2 is not expected and in fact is detrimental to some of our other code that depends on IsChanged being false (our own PK "next id" handling code).

This seems like a bug. Can you fix it or else tell me what’s happening?

Here is some sample code to demonstrate the two scenarios (derived from the code example in the documentation on serialization in compact format):


            // serialize and deserialize an entity NOT participating in an inheritance hierarchy
            CONSUMEREntity consumer = new CONSUMEREntity();
            consumer.NAME1 = "test";
            StreamWriter writer = new StreamWriter("c:\\testconsumer.xml");
            string consumerXml = String.Empty;
            consumer.WriteXml(
                XmlFormatAspect.Compact | XmlFormatAspect.DatesInXmlDataType | XmlFormatAspect.MLTextInCDataBlocks, out consumerXml);
            writer.Write(consumerXml);
            writer.Close();

            // now read it back
            StreamReader reader = new StreamReader("c:\\testconsumer.xml");
            string xmlFromFile = reader.ReadToEnd();
            reader.Close();
            CONSUMEREntity consumerFromXml = new CONSUMEREntity();
            consumerFromXml.ReadXml(xmlFromFile);
            // NOTE: consumer.ID.IsChanged == false and consumerFromXml.ID.IsChanged == false ALL AS EXPECTED
            
            // serialize and deserialize an entity THAT IS participating in an inheritance hierarchy: DeliveryChannelEntity derives from ChannelEntity
            DELIVERYCHANNELEntity deliverychannel = new DELIVERYCHANNELEntity();
            deliverychannel.NAME = "test channel";
            writer = new StreamWriter("c:\\test.xml");
            string deliveryChannelXml = String.Empty;
            deliverychannel.WriteXml(
                XmlFormatAspect.Compact | XmlFormatAspect.DatesInXmlDataType | XmlFormatAspect.MLTextInCDataBlocks, out deliveryChannelXml);
            writer.Write(deliveryChannelXml);
            writer.Close();

            // now read it back
            reader = new StreamReader("c:\\test.xml");
            xmlFromFile = reader.ReadToEnd();
            reader.Close();
            DELIVERYCHANNELEntity dcFromXml = new DELIVERYCHANNELEntity();
            dcFromXml.ReadXml(xmlFromFile);
            // NOTE: deliveryChannel.ID.IsChanged == false but dcFromXml.ID.IsChanged == true WHICH IS NOT EXPECTED!

In the serialized XML: For consumer:

<Fields>
<ID>
  <CurrentValue Type="Unknown" /> 
  <DbValue Type="Unknown" /> 
  <IsChanged>False</IsChanged> 
  <IsNull>False</IsNull> 
</ID>

For DeliveryChannel:

<Fields>
<ID>
  <CurrentValue Type="Unknown" /> 
  <DbValue Type="Unknown" /> 
  <IsChanged>False</IsChanged> 
  <IsNull>False</IsNull> 
</ID>

So the serialized version is correct. The problem must be in the deserialization code.

Please help!

(using v2.0 - About: August 3rd, 2006, ORM versiono: 2.0.0.60717)

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 18-Sep-2006 16:54:45   

Upgrade to the latest ORMSUpportclasses first. You're using the ones from July 17th.

Frans Bouma | Lead developer LLBLGen Pro
takb
User
Posts: 150
Joined: 12-Mar-2004
# Posted on: 19-Sep-2006 03:18:20   

Otis wrote:

Upgrade to the latest ORMSUpportclasses first. You're using the ones from July 17th.

Ok, I upgraded to the latest (released 11th Sept, about: September 8th, ORMSupport classes: 2.0.0.60911), ensured that my custom entity initialisation code was removed then regenerated my code.

Unfortunately the same behaviour exists. After deserialisation of a new entity, the unmodified PK field from the base entity is marked as IsChanged==true. The object is an instance of a derived object and so has 2 fields in the PrimaryKeyFields collection. The second field (which is the PK of the subclass and also of course the FK to the base class) is however correctly marked as IsChanged==false.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 19-Sep-2006 09:29:09   

Ok, I'll check it out.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 19-Sep-2006 12:50:19   

I cant reproduce it:


[Test]
public void XmlDeserializationPKUnChangedTest()
{
    ManagerEntity toSerialize = new ManagerEntity();
    toSerialize.Name = "John Foo";
    Assert.IsFalse(toSerialize.Fields[(int)ManagerFieldIndex.Id_Employee].IsChanged);
    Assert.IsFalse(toSerialize.Fields[(int)ManagerFieldIndex.Id].IsChanged);
    string xml = String.Empty;
    toSerialize.WriteXml(XmlFormatAspect.Compact | XmlFormatAspect.DatesInXmlDataType | XmlFormatAspect.MLTextInCDataBlocks, out xml);
    ManagerEntity deserialized = new ManagerEntity();
    deserialized.ReadXml(xml);
    Assert.IsFalse(toSerialize.Fields[(int)ManagerFieldIndex.Id_Employee].IsChanged);
    Assert.IsFalse(toSerialize.Fields[(int)ManagerFieldIndex.Id].IsChanged);
}

Frans Bouma | Lead developer LLBLGen Pro
takb
User
Posts: 150
Joined: 12-Mar-2004
# Posted on: 19-Sep-2006 13:59:49   

Otis wrote:

I cant reproduce it:

disappointed Ok I'll see what else I can find...

Thanks for looking. I'll let you know what the problem is (if I find it).

takb
User
Posts: 150
Joined: 12-Mar-2004
# Posted on: 19-Sep-2006 14:18:42   

Woops. Bug in your test. Last two Assert statements should read:


    Assert.IsFalse(deserialized.Fields[(int)ManagerFieldIndex.Id_Employee].IsChanged);
    Assert.IsFalse(deserialized.Fields[(int)ManagerFieldIndex.Id].IsChanged);

And the test now fails for me.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 19-Sep-2006 15:06:18   

Whoa good catch! flushed

Will dig right into it

(edit) reproduced!

Ok, found the cause. When the subtype's PK is written by the deserializer, even if its done in the ForcedCurrentvaluewrite routine, the supertype pk field, which is linked to it (so setting one, will set the other one) is set by the same value, and no matter what happens, that makes IsChanged get set to true.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 19-Sep-2006 15:40:20   

Fixed in next build (released later today)

Frans Bouma | Lead developer LLBLGen Pro
takb
User
Posts: 150
Joined: 12-Mar-2004
# Posted on: 19-Sep-2006 16:04:37   

Cheers Frans.

takb
User
Posts: 150
Joined: 12-Mar-2004
# Posted on: 20-Sep-2006 01:29:50   

Frans, there's a problem with the build. You've updated the v1.0 and v1.1 libraries but not the v2.0 libraries. The v2 libararies are still all marked 11th Sept (and I've proven that they still have the bug).

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 20-Sep-2006 08:19:37   

The build is made automatically, with finalbuilder, so it should be OK, I'll check it out.. (edit), indeed, a builderror somewhere. Strange, I'll rebuild and re-upload the code. Sorry for this.

(edit) It's now available.

Frans Bouma | Lead developer LLBLGen Pro