将 ServiceStack.Net 从 4.0.39 升级到 4.5.6 后,OrmLite 模型未填充

OrmLite Model not populating after upgrading ServiceStack.Net from 4.0.39 to 4.5.6

将 ServiceStack.Net 从 4.0.39 升级到 4.5.6 后,我们发现有些情况下模型未被填充,但它确实包含正确数量的记录。每条记录的属性都是默认值。恢复到 4.0.39 时一切正常。

我们想知道是否有需要更新的更改?我们没有注意到文档中的任何内容,用法看起来与示例相似。

如果不知道答案,下一个最简单的找出正在发生的事情的方法是什么? (看起来可能需要下载源代码并编译和引用新的 4.5.6 OrmLite,但是有没有更简单的选择?)

这是一个简单的例子。 https://gist.github.com/anonymous/bb514062a7d97b0ff4b0a546ef315765

using System;
using NUnit.Framework;
using ServiceStack;
using ServiceStack.Configuration;
using ServiceStack.DataAnnotations;
using ServiceStack.OrmLite;

namespace MyCompany.Tests
{
    public class OrmLiteModelArrayTests
    {
        [Alias("color")]
        public class ColorModel
        {
            public string Color { get; set; }
            public string Value { get; set; }
        }

        public class ColorJsonModel
        {
            public int Id { get; set; }
            public string ColorJson { get; set; }
        }

        [Test]
        public void test_model_with_array_to_json()
        {

            OrmLiteConfig.DialectProvider = PostgreSqlDialect.Provider;

            var testingConn = ConfigUtils.GetConnectionString("testing");

            using (var db = testingConn.OpenDbConnection())
            {
                db.DropAndCreateTable();

                db.Insert(new ColorModel { Color = "red", Value = "#f00" });
                db.Insert(new ColorModel { Color = "green", Value = "#0f0" });
                db.Insert(new ColorModel { Color = "blue", Value = "#00f" });
                db.Insert(new ColorModel { Color = "cyan", Value = "#0ff" });
                db.Insert(new ColorModel { Color = "magenta", Value = "#f0f" });
                db.Insert(new ColorModel { Color = "yellow", Value = "#ff0" });
                db.Insert(new ColorModel { Color = "black", Value = "#000" });

                const string sql = @"SELECT 1::integer AS id
                                        , json_agg(color.*) AS color_json
                                    FROM color;";

                var results = db.Select<ColorJsonModel>(sql);

                Assert.That(results.Count, Is.EqualTo(1));

                foreach (var result in results)
                {
                    Console.WriteLine("{0}".Fmt(result.ColorJson));
                    Assert.That(result.Id, Is.EqualTo(1));
                    Assert.That(result.ColorJson, Is.Not.Null);
                }

            }
        }

        [Test]
        public void test_model_with_array_and_json()
        {

            OrmLiteConfig.DialectProvider = PostgreSqlDialect.Provider;

            var testingConn = ConfigUtils.GetConnectionString("testing");

            using (var db = testingConn.OpenDbConnection())
            {
                db.DropAndCreateTable<ColorModel>();

                db.Insert(new ColorModel { Color = "red", Value = "#f00" });
                db.Insert(new ColorModel { Color = "green", Value = "#0f0" });
                db.Insert(new ColorModel { Color = "blue", Value = "#00f" });
                db.Insert(new ColorModel { Color = "cyan", Value = "#0ff" });
                db.Insert(new ColorModel { Color = "magenta", Value = "#f0f" });
                db.Insert(new ColorModel { Color = "yellow", Value = "#ff0" });
                db.Insert(new ColorModel { Color = "black", Value = "#000" });

                // SQL contains array and json aggs.
                // We usually have ARRAY fields defined in the db, but when
                // retrieved we json-ize them. In otherwords the array exists in the tables/views.
                // We use SELECT.* which would contain the ARRAY field.
                // Array fields are not used in any of our models and should not cause the other
                // fields in the model to not be populated.
                const string sql = @"SELECT 1::integer AS id
                                            , json_agg(color.*) AS color_json
                                            , array_agg(color.*) AS color_array
                                    FROM color;";

                var results = db.Select<ColorJsonModel>(sql);

                Assert.That(results.Count, Is.EqualTo(1));

                foreach (var result in results)
                {
                    Console.WriteLine("{0}".Fmt(result.ColorJson));
                    Assert.That(result.Id, Is.EqualTo(1));
                    Assert.That(result.ColorJson, Is.Not.Null);
                }

            }
        }
    }
}

更新:

更奇怪的是,我们发现了一个示例,其中总共返回了 7 条记录,但 7 条记录中有 6 条具有默认空值,最后一条(第 7 条)记录被完全填充。

更新 2:

问题是处理 SELECT * 中包含但未在 C# 模型中使用的 ARRAY 字段。

描述中的示例代码无法编译,但我已经使用最新版本的 OrmLite 测试了最接近的工作版本,并且按预期工作:

[Alias("my_table")]
public class MyModel
{
    public int MyId { get; set; }
    public int BlahId { get; set; }
    public string Name { get; set; }
}

using (var db = OpenDbConnection())
{
    db.DropAndCreateTable<MyModel>();

    db.Insert(new MyModel { MyId = 1, BlahId = 2, Name = "foo" });
    db.Insert(new MyModel { MyId = 2, BlahId = 3, Name = "bar" });

    var results = db.GetMyModels(1, 2);

    Assert.That(results.Count, Is.EqualTo(1));
    Assert.That(results[0].MyId, Is.EqualTo(1));
    Assert.That(results[0].BlahId, Is.EqualTo(2));
    Assert.That(results[0].Name, Is.EqualTo("foo"));
}

public static class CustomSqlExtensions
{
    public static List<MyModel> GetMyModels(this IDbConnection db, int myId, int blahId)
    {
        const string sql = @"SELECT * FROM my_table WHERE my_id = @myId AND blah_id = @blahId";
        return db.Select<MyModel>(sql, new { myId, blahId });
    }
}

虽然它不会在这里产生影响,但在使用自定义 SQL 时,您应该像 SqlList 一样使用 Custom SQL APIs,例如:

return db.SqlList<MyModel>(sql, new { myId, blahId });

问题highlighted from this Gist

const string sql = @"SELECT 1::integer AS id
                            , json_agg(color.*) AS color_json
                            , array_agg(color.*) AS color_array
                    FROM color;";

var results = db.Select<ColorJsonModel>(sql);

在 Npgsql 中使用未知的 PostgreSQL 类型

是由于 Npgsql 不知道 array_agg 类型是什么所以会抛出异常:

字段 'color_array' 具有 Npgsql 当前未知的类型 (OID 101487)

尝试读取行数据集及其 GetValues() 批次 API 时。我添加了一个 fallback in this commit,如果 GetValues() 批处理 API 失败,它将回退到单独的读取读取,这将解决这个问题。

但是这会抛出一个不是最佳的异常,您可以告诉 OrmLite 避免使用批处理 GetValues() API 完全通过告诉它始终使用单独的字段提取:

OrmLiteConfig.DeoptimizeReader = true;

这将避免尝试使用 GetValues() 并避免其异常。