让 ORMLite 对结构使用正确的序列化

2024-01-08

tl;dr:

我正在结构上注册序列化器和反序列化器。
序列化器未被调用,但解串器被调用。

我怎样才能解决这个问题?
它适用于引用类型,并且执行JsConfig<Position>.TreatValueAsRefType = true;也没有帮助。


长版:

我使用 ORMLite 存储两种复杂类型:Position(一个结构,来自我们无法控制的外部库 DotSpatial)和 Tuple。

为了能够正确地从数据库中存储/读取它们,我定义了它们的序列化器和反序列化器:

// Struct. Called by position.ToJsv(), NOT called by ORMLite's 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");
};

调试

使用 ORMLite 从数据库读取数据时,解串器中会遇到断点:connection.Where<T>(item => item.Foo == bar).
使用 ORMLite 写入数据库时​​,不会命中序列化器中的断点:connection.Insert(item).

我认为序列化器可能没有正确注册,所以我打电话.ToJsv()在物体上。

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.

当遇到断点时,str =00°00'02.7451"N,013°29'17.3270"W.
但是当使用 ORMLite 插入时,断点没有命中,我在数据库中得到了值,例如00°00'02,7451"N;013°29'17,3270"W - 由于文化原因,请注意逗号.

数据库正在保存与文化相关的价值观! :(

Attempts

由于这种情况仅发生在结构上,因此我尝试将类型注册为引用类型,但这似乎不起作用。

JsConfig<Position>.TreatValueAsRefType = true;

Update:

我正在使用ORMLite.PostgreSQLNuget 包(v 3.9.70)。它包括 ServiceStack.Text (v 3.9.70) 和 Npgsql (v 2.0.11)。

我想尝试从源代码管理中获取代码并直接调试它,但现在我没有时间。

The Positionstruct 是在外部库中定义的,我无法更改。

极简样本

我已经上传了一个极简主义样本https://gist.github.com/aneves/7830776 https://gist.github.com/aneves/7830776,显示以下输出:

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 . . .

UPDATE:

检查了源码后OrmLite https://github.com/ServiceStack/ServiceStack.OrmLite在 GitHub 上,似乎:

  • JsConfig<Position>.TreatValueAsRefType would never将数据序列化到数据库时进行检查。
  • 对于反序列化 OrmLite 会always call TypeSerializer.DeserializeFromString,这就是为什么你的场景只在那个方向起作用。

为了解决这个问题,我已经提交了a patch https://github.com/mayerwin/ServiceStack.OrmLite/commit/67f60b8fc9dba75fef8ef6a25ae75880b39873f9到主存储库。同时,非常欢迎您使用此补丁重新编译 OrmLite,或者直接使用我为您提供的重新编译版本(基于 4.0.3)here http://erwinmayer.com/dl/ServiceStack.OrmLite.zip代替 NuGet 中的相应文件之一。

我希望这个修复将被纳入下一个正式版本以及 3.* 分支中。

原答案:

如果您可以控制 Position 结构(似乎并非如此),您是否尝试过重写 ToString() ?如果我没记错的话,OrmLite 应该这么称呼它:

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);
    }
}

它可能无法解决 SerializeFn 未被调用的问题,但对于您的目标而言可能足够好,至少在错误修复之前是这样。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

让 ORMLite 对结构使用正确的序列化 的相关文章

随机推荐