Make ORMLite use proper serialization for structures

TL; dr:

I register the serializer and deserializer in the structure. The serializer is not called, but there is a deserializer.

How can i fix this? It works correctly on reference types, and doing JsConfig<Position>.TreatValueAsRefType = true; also did not help.


Long version:

I save two complex types using ORMLite: Position (structure, from the external DotSpatial library that we do not control) and Tuple.

To be able to properly store / read them from the database, I defined their serializers and deserializers:

 // Struct. Called by position.ToJsv(), NOT called by ORMLite connection.Insert() . JsConfig<Position>.SerializeFn = position => { string str = position.ToString(null, CultureInfo.InvariantCulture); return str; // Breakpoint here. }; // Struct. Called in both. JsConfig<Position>.DeSerializeFn = position => Position.Parse(position, CultureInfo.InvariantCulture); // Reference type. Works fine. JsConfig<Tuple<double, double>>.SerializeFn = tuple => string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", tuple.Item1, CultureInfo.InvariantCulture.TextInfo.ListSeparator, tuple.Item2 ); // Works fine too. JsConfig<Tuple<double, double>>.DeSerializeFn = tuple => { var values = tuple.Split(new[] { CultureInfo.InvariantCulture.TextInfo.ListSeparator }, StringSplitOptions.None); double item1, item2; if (values.Length == 2 && double.TryParse(values[0], out item1) && double.TryParse(values[1], out item2)) { var result = new Tuple<double, double>(item1, item2); return result; } throw new ArgumentException("Could not parse easting and northing from database; malformatted?", "tuple"); }; 

Debugging

The breakpoint in the deserializer gets when reading from the database using ORMLite: connection.Where<T>(item => item.Foo == bar) .
Γ‚ The breakpoint in the serializer does not fall when writing to the database using ORMLite: connection.Insert(item) .

I thought that maybe the serializer was not registered properly, so I called .ToJsv() on the object.

 var lat = Latitude.Parse("00Β°00'02.7451\"N", CultureInfo.InvariantCulture); var lon = Longitude.Parse("013Β°29'17.3270\"W", CultureInfo.InvariantCulture); Position pos = new Position(lat, lon); string foo = pos.ToJsv(); // Works, hits the breakpoint. 

When the breakpoint is reached, str = 00Β°00'02.7451"N,013Β°29'17.3270"W
But when inserting with ORMLite, the breakpoint does not hit, and I get values ​​in the database, such as 00Β°00'02,7451"N;013Β°29'17,3270"W - pay attention to commas due to culture.

The database stores culture-dependent values ​​!: (

Attempts

Since this only happens in structures, I tried to register a type that would be considered as a reference type, but that didn't seem to work.

 JsConfig<Position>.TreatValueAsRefType = true; 

Update:

I am using the ORMLite.PostgreSQL Nuget package (v 3.9.70). It includes ServiceStack.Text (v 3.9.70) and Npgsql (v 2.0.11).

I want to try to get the code from the source control and debug it directly, but so far I don't have time.

Position structure is defined in an external library, which I cannot change.

Minimalist pattern

I downloaded a minimalist sample at https://gist.github.com/aneves/7830776 , which shows the following output:

 Thing, current culture: 12,6;10,9 Thing, invariant culture: 12.6,10.9 Thing, from Jsv: "12,6;10,9" >> deserializing 10;35 >> Could not parse value, it is malformed. (10;35) Found this: Box[A: 0;0] Press any key to continue . . . 
+3
c # serialization servicestack ormlite-servicestack
source share
2 answers

UPDATE:

After checking the source code of OrmLite on GitHub, it turned out that:

  • JsConfig<Position>.TreatValueAsRefType will never be checked when serializing data in the database.
  • For deserialization, OrmLite will always call TypeSerializer.DeserializeFromString , so your script only worked in that direction.

To fix the problem, I sent the patch to the main repository. In the meantime, you like either to recompile OrmLite with this patch, or just use the recompiled version (based on 4.0.3) that I provided to you here instead of one of the corresponding file from NuGet.

I hope that this fix will be included in the next official release, as well as in branch 3. *.

ORIGINAL RESPONSE:

If you have control over the Position structure (which seems to be wrong), have you tried overriding ToString ()? OrmLite should call it if I remember correctly:

 struct Position { public override ToString(object o, CultureInfo culture) { /* Your serialization */ } public override ToString() { // Will be used by OrmLite to serialize position.ToString(null, CultureInfo.InvariantCulture); } } 

It may not decide SerializeFn <> to not be called, but it may be good enough for your purpose, at least until the error is fixed.

+3
source share

If possible, I would prefer to implement the correct solution.

Now I fix the problem by defining my own MyPosition class, which mimics the structure by defining implicit statements.
(Do not consider zeros, they are related to how ToString overloads were implemented for the position.)

 JsConfig<MyPosition>.SerializeFn = position => position.ToString(null, CultureInfo.InvariantCulture); JsConfig<MyPosition>.DeSerializeFn = position => Position.Parse(position, CultureInfo.InvariantCulture); 

 public class MyPosition { public Latitude Latitude { get; set; } public Longitude Longitude { get; set; } public override string ToString() { return ToString(null, CultureInfo.CurrentCulture); } public string ToString(CultureInfo culture) { return ToString(null, culture); } public string ToString(string format, CultureInfo culture) { var pos = new Position(Latitude, Longitude); return pos.ToString(null, culture); } public static implicit operator MyPosition(Position toConvert) { return new MyPosition { Latitude = toConvert.Latitude, Longitude = toConvert.Longitude }; } public static implicit operator Position(MyPosition toConvert) { return new Position(toConvert.Latitude, toConvert.Longitude); } } 
+2
source share

All Articles