【问题标题】:RavenDB: Deserializing nested arraysRavenDB:反序列化嵌套数组
【发布时间】:2015-03-09 20:08:18
【问题描述】:

假设我有以下类要序列化并存储为 RavenDB 的文档:

public class Block
{
    public string Id { get; set; }
    public List<List<dynamic>> data { get; set; }
}

存储后,在数据库中可以看到这样的文档:

{
"Id": "f539770a",
"columns": [ 
              [ 90, 91, 92, 93, 94 ], 
              [ "C", "D", "A", "B", "C" ] 
           ] }

我想执行一个查询来检索“列”字段中的第 N 个值列表:

session.Query<Block>().Where(b => b.Id == "f539770a").Select(b =>b.columns[i]);

我得到以下错误:

{"无法将当前 JSON 对象(例如 {\"name\":\"value\"})反序列化为类型 'System.Collections.Generic.List`1[System.Object]',因为该类型需要JSON 数组(例如 [1,2,3])以正确反序列化。\r\n要修复此错误,请将 JSON 更改为 JSON 数组(例如 [1,2,3])或更改反序列化类型,使其可以从 JSON 对象反序列化的普通 .NET 类型(例如,不是像整数这样的原始类型,不是像数组或列表这样的集合类型)。也可以将 JsonObjectAttribute 添加到该类型以强制它从 JSON 对象反序列化.\r\n路径'__document_id'。"}

查询似乎正常工作(服务器返回 http 200),但存在客户端反序列化问题。

我错过了什么吗?

谢谢!!

更新:

我更改了数据结构,因为错误似乎表明:

public class Column
{
    public List<dynamic> data { get; set; }
}

public class Block
{
    public string Id { get; set; }
    public List<Column> columns { get; set; }
}

存储的文档是这样的:

{
"Id": "f539770a",
"columns": [
             { "data": [ 95, 96, 97, 98, 99 ] },
             { "data": [ "D", "A", "B", "C", "D" ] }
           ]}

执行此查询后:

session.Query<Block>().Include<Block>(b => b.columns).Where(b => b.parentFileId == dbFileDescriptor.Id).Select(b => b.columns[i])

我没有异常,但是嵌套数组没有加载:

【问题讨论】:

  • 你想用Select(b =&gt; b.columns[i]);做什么?
  • 是的,有一个文档数组,我只想检索索引 i 处的文档。
  • 查看我编辑的答案。

标签: ravendb nosql


【解决方案1】:

删除Include。那不是它的用途。 Include 用于预加载对其他文档的引用,因此您不必进行多次数据库访问。您可能正在让 RavenDB 查找 Block's 及其对应的 Column 文档。请参阅文档here

session.Query<Block>().Where(b => b.parentFileId == dbFileDescriptor.Id).Select(b => b.data[i]);

编辑

如果您要通过 Id 查看某些内容,请使用 Load 而不是 Query

session.Load<Block>("f539770a").data[i];

我验证了这适用于使用 RavenDB.Tests.Helpers nuget 包和 Shouldly 进行断言的 raven 单元测试。

    public class SoQuestion : RavenTestBase
    {
        [Fact]
        public void GetBlock_Success()
        {
            using (var docStore = NewDocumentStore())
            {
                using (var session = docStore.OpenSession())
                {
                    session.Store(new Block
                    {
                        Id = "f539770a",
                        data = new List<List<dynamic>>()
                        {
                            new List<dynamic>()
                            {
                                90,
                                91,
                                92,
                                93,
                                94
                            },
                            new List<dynamic>()
                            {
                                "C",
                                "D",
                                "A",
                                "B",
                                "C"
                            }
                        }
                    });
                    session.SaveChanges();
                }

                docStore.WaitForStaleIndexesToComplete();

                //Act
                var block = GetBlock(docStore);

                //Assert
                block.ShouldNotBe(null);
                block.data.ShouldNotBeEmpty();
            }
        }

        private Block GetBlock(IDocumentStore documentStore)
        {
            using (var session = documentStore.OpenSession())
            {
                return session.Load<Block>("f539770a");
            }
        }

        public class Block
        {
            public string Id { get; set; }
            public List<List<dynamic>> data { get; set; }
        }
    }

【讨论】:

  • 还是不行。 Load().columns[i] 检索整个块,然后在本地选择 column[i]。这个想法是通过仅请求所需的元素来最小化数据库和客户端之间所需的传输。顺便问一下,RavenDB 是否支持这种部分数据检索,或者一切都在客户端的内存中?
  • 我正在寻找与您在 MongoDB 中使用查询类似的行为:this.DBFileBlocks.Find(query).SetFields(Fields.Include(fb => fb.rows[ x])。这仅传输选定的数据,而不是整个文档。
  • 因此,如果我理解正确,您是在 for 循环中的文档中选择这些数组。首先只加载文档。您将它保存在内存中,然后您可以遍历 data 元素的列表。那将只是 1 次访问数据库。加载整个文档比使用文档关系要高效得多。如果比通过网络传输的东西快得多,则反序列化整个文档。现在,如果您希望您的文档非常大,那么您将遇到不同的问题。 (1 MB+/doc)
  • 整个问题可以归结为“我想检索数组的第 N 个元素,因为这样的元素也是一个数组”。它只是预测结果,Select 应该做什么。如果在客户端执行 Select,那么这将是数据库可能具有的最粗略的查询实现,我希望 RavenDB 不会出现这种情况。
  • 因此在对文档进行建模时应牢记这一点。如果您不想要这种行为,请将您的子类放入他们自己的文档中。或者,您可以尝试弄清楚如何将其放入静态索引中。
猜你喜欢
  • 2019-09-22
  • 2019-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多