WriteXml/ReadXml for classes inherited from Base Class

Posts   
 
    
tmarosti
User
Posts: 8
Joined: 03-May-2005
# Posted on: 19-Jul-2005 01:47:59   

In SelfServicing, I have a LLBLGen generated class called Person. I created a class called Patient that inherits from this class. This new class has properties of datatype string that are not part of the Person class but the code contained in the get and set refers to properties in the Person class.

_ Public Class Patient Inherits PersonEntity

    Public Property DOB() As Date
        Get
            Return Me.BirthTime
        End Get
        Set(ByVal Value As Date)
            Me.BirthTime = Value
        End Set
    End Property

End Class _

When I generate XML from the Patient class and read it back in, I get an error (Specified argument was out of the range of valid values. Parameter name: Index was out of range. Must be non-negative and less than the size of the collection.) when it tries to set the properties from the Patient class.

_ Dim writer As New StreamWriter("patient.xml") Dim patientXml As String = String.Empty Dim myPatient As New Patient(13) If Not myPatient.IsNew Then myPatient.WriteXml(patientXml) writer.Write(patientXml) End If writer.Close()

        Dim reader As New StreamReader("patient.XML")
        Dim xmlFromFile As String = reader.ReadToEnd()
        reader.Close()
        Dim patientFromXml As New Tables.Patient
        patientFromXml.ReadXml(xmlFromFile)

_

I have debugged the problem down to the following line in EntityBase.Xml2Entity,

properties[currentElement.Name].SetValue(this, typeConverter.XmlValueToObject(elementTypeName, xmlValue));

where this = Patient class, currentElement.Name = "DOB", elementTypeName = "System.Date", and xmlValue = "622093824000000000"

Any ideas as to what I might be doing wrong?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 19-Jul-2005 10:26:29   

you specify: Tables.Patient

is that another patient class? The reason I ask is that the properties in 'patient' when you read back the xml don't contain a property called 'DOB'. Could you check that for me please in the debugger if that's the case?

The Xml2Entity routine reflects the type it's in to get the properties it exposes. Then it reads the xml and when it runs into a property and its value, it sets the property using the reflected properties set. Normally this should be there, if it's the same type.

(The XML is produced the same way: properties are reflected, all fields are filtered out, as these are stored separately, and the rest is exported into the xml).

Frans Bouma | Lead developer LLBLGen Pro
tmarosti
User
Posts: 8
Joined: 03-May-2005
# Posted on: 19-Jul-2005 18:57:55   

sorry, Tables is a typo. It is the same class. In the debugger, I examine the locals window and if I expand 'this' I can see the 'Patient' class plus some other LLBLGen properties such as 'EntityFactoryToUse' and 'Fields'. If I exapnd the 'Patient' class then I see the 'PersonEntity' class but I also see the 'DOB' property.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 19-Jul-2005 20:37:51   

Ok. I'll see if I can reproduce it here. Be sure to use the latest runtime libraries in any case.

Frans Bouma | Lead developer LLBLGen Pro
tmarosti
User
Posts: 8
Joined: 03-May-2005
# Posted on: 20-Jul-2005 00:48:49   

Found the problem but I am not sure how to correct it. We are confronted with a situation where the application we are developing must be able to support disconnected clients using laptops. The idea is that these laptops would have a completely identical SQL database as the central server database. The user would enter data on the laptop and then, at a later time, connect to the central network and save the data. I would like to use a technique of serializing the data to XML files and then de-serialize them on the central network. I am getting this error whenever I am de-serializing a record from a file and that record does not exist in the central database. Any ideas how to get around this?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 20-Jul-2005 10:56:51   

I added a similar property to an entity (customer). I inserted a new customer, then removed it from the db (using another entity instance), then serialized it to xml, then deserialized it into another instance using the same xml.

It worked without a problem. confused

What I can advice you is (as I can't reproduce the problem so I don't know the cause): 1) either upgrade to the latest version. 2) mark the DOB property with XmlIgnore attribute. As it sets a field of the entity, this property is not necessary in the XML, as the value is already passed on in the fields. So the DOB property isn't serialized into the XML.

If your problem is that you can't save the entity deserialized into the db, that's of course due to the fact that the entity deserialized isn't new, so it results in an update statement, though as there's no entity yet, that fails.

Frans Bouma | Lead developer LLBLGen Pro
tmarosti
User
Posts: 8
Joined: 03-May-2005
# Posted on: 20-Jul-2005 19:09:40   

Does it matter that I used two seperate applications, one for writing and one for reading, with seperate databases (with identical schemas) for each application?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 21-Jul-2005 10:58:10   

tmarosti wrote:

Does it matter that I used two seperate applications, one for writing and one for reading, with seperate databases (with identical schemas) for each application?

That should be ok, as long as the generated code is the same, as in: using the same types.

Frans Bouma | Lead developer LLBLGen Pro
tmarosti
User
Posts: 8
Joined: 03-May-2005
# Posted on: 26-Jul-2005 21:26:27   

Ok, I solved my first issue. I am not that familiar with reflection so I did not know that the debugger would not automatically step into the property being reflected. Once I put a breakpoint in the property code I found the problem to be custom code that I was not aware of.

My next problem is one that you alluded to in a previous post to this thread:

If your problem is that you can't save the entity deserialized into the db, that's of course due to the fact that the entity deserialized isn't new, so it results in an update statement, though as there's no entity yet, that fails.

I found another thread where you suggest setting the IsChanged property for the fields in the object. However, I am currently working on a simple database synchronization module for our application. The most important property to me is the IsNew property. I need to be able to not only set the IsChanged property but also verify the existence of the object using the PK and I need to do this for all of the related objects.

I am trying to write code using the GetDependentRelatedEntities, GetDependingRelatedEntities, and GetMemberEntityCollections functions. I assume that the FetchUsingPK function would be the best method for determining the existence of the record in the database, but that requires casting the entity in the collection to the appropriate entity Type. Is there any way to write code to cast the entity without programming a giant Case structure that checks the entity against all types?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 27-Jul-2005 11:06:34   

tmarosti wrote:

My next problem is one that you alluded to in a previous post to this thread:

If your problem is that you can't save the entity deserialized into the db, that's of course due to the fact that the entity deserialized isn't new, so it results in an update statement, though as there's no entity yet, that fails.

I found another thread where you suggest setting the IsChanged property for the fields in the object. However, I am currently working on a simple database synchronization module for our application. The most important property to me is the IsNew property. I need to be able to not only set the IsChanged property but also verify the existence of the object using the PK and I need to do this for all of the related objects.

I am trying to write code using the GetDependentRelatedEntities, GetDependingRelatedEntities, and GetMemberEntityCollections functions. I assume that the FetchUsingPK function would be the best method for determining the existence of the record in the database, but that requires casting the entity in the collection to the appropriate entity Type. Is there any way to write code to cast the entity without programming a giant Case structure that checks the entity against all types?

Take note that the GetDependent... GetMember... GetDepending.. routines return objects or collections which are loaded in memory, they don't consult the database.

If you want to check if an entity already exists, you should use a scalar query, if the entity has a single field PK. You can determine what the PK field is by checking IEntity.Fields.PrimaryKeyFields, which contains the IEntityField objects which are the PK for that entity. Use the TypedListDAO.GetScalar method, as universal way to perform a getscalar.

You can also use a dyn. list, setup by the fields of the entity and a filter build by the PK field(s) and perform a fetch.

You can also do:


entity.SaveFields("BeforeRefetch");
bool refetchResult = entity.Refetch();
entity.RollbackFields("BeforeRefetch");
if(refetchResult)
{
// is there, so don't set IsNew
}
else
{
// isn't there
}

Frans Bouma | Lead developer LLBLGen Pro