如何加载<;T>;不使用默认ID生成策略时,受集合约束的RavenDB文档

如何加载<;T>;不使用默认ID生成策略时,受集合约束的RavenDB文档,ravendb,ravendb4,Ravendb,Ravendb4,在Ravendb4(v4.0.3-patch-40031)中,我有两种文档类型:Apple和Orange。两者具有相似但又截然不同的特性。我在运行时的代码中遇到了一个bug,有时候会提供一个苹果的ID,但会返回一个橙色。吓人 深入研究一下,这有点道理。但我正在努力寻找一个合适的解决方案 来吧。在RavenDB中,我将一个Apple存储为文档: id: "078ff39b-da50-4405-9615-86b0d185ba17" { "Name": "Elstar", "@meta

在Ravendb4(v4.0.3-patch-40031)中,我有两种文档类型:
Apple
Orange
。两者具有相似但又截然不同的特性。我在运行时的代码中遇到了一个bug,有时候会提供一个苹果的ID,但会返回一个橙色。吓人

深入研究一下,这有点道理。但我正在努力寻找一个合适的解决方案

来吧。在RavenDB中,我将一个
Apple
存储为文档:

id: "078ff39b-da50-4405-9615-86b0d185ba17"
{
    "Name": "Elstar",
    "@metadata": {
        "@collection": "Apples",
        "Raven-Clr-Type": "FruitTest.Apple, FruitTest"
    }
}
在本例中,假设数据库中没有存储
Orange
文档。我希望这次测试能够成功:

//排列-使用Orange集合中不存在的苹果ID
变量id_of_apple=“078ff39b-da50-4405-9615-86b0d185ba17”;
//装一个橘子
var target=wait_session.LoadAsync(“078ff39b-da50-4405-9615-86b0d185ba17”);
//assert-应该为null,因为没有带有该Id的橙色
target.Should().BeNull(因为:“提供的ID不是桔子而是苹果”);
。。。但它失败了。发生的情况是文档ID存在,因此RavenDB加载文档。不管它是什么类型的。它尝试自动映射属性。我预期或错误地假设加载类型说明符会将查找限制到该特定文档集合。相反,它在整个数据库中获取+映射,而不是将其限制为
类型
。因此,该行为不同于
.Query
,后者对集合没有约束

需要注意的是,通过将Id设置为
string.Empty
(符合),我使用guid作为身份策略。我假设默认的ID策略,如
entityname/1001
,不会有这个问题

但他们并没有真正提到这是否是故意的。它只说:“从数据库下载文档并将其转换为实体。”

但是,出于某些原因,我确实希望将加载操作约束到单个集合。或者,更好的说法是,尽可能高效地从特定集合按ID加载文档。如果它不存在,则返回null

好了,有两种方法可以实现这一点:

  • 使用更昂贵的
    .Query.Where(x=>x.Id==Id)
    ,而不是
    .Load(Id)
  • 首先执行
    .Load(id)
    ,然后检查(~不知何故,请参见底部)它是否是集合T的一部分
  • 我的问题可以概括为两个问题:

  • 有没有比上述两种选择更有效或稳定的方法
  • 如果没有,在这两个选项中,在性能和稳定性方面推荐哪一个
  • 特别是对于第二个问题,很难正确衡量这一点。至于稳定性,例如没有副作用,我想对RavenDB内部结构有更深入了解或经验的人可能会对此有所启发

    注意:问题假设所解释的行为是故意的,而不是RavenDB bug

    ~z~不知怎的,会是:

    公共异步任务获取(字符串id)
    {
    var instance=wait_session.LoadAsync(id);
    if(instance==null)返回null;
    //收集的“不知何故”检查
    var expectedTypeName=string.Concat(typeof(T).Name,“s”);
    var actualTypeName=_session.Advanced.GetMetadataFor(实例)[Constants.Documents.Metadata.Collection].ToString();
    如果(实际类型名称!=预期类型名称)
    {
    //边缘盒:苹果!=橙色
    返回null;
    }
    返回实例;
    }
    
    如何繁殖 更新2018/04/19-在有用的评论后添加了此可复制样品(谢谢)

    型号

    公共接口IFruit
    {
    字符串Id{get;set;}
    字符串名称{get;set;}
    }
    公共级苹果:IFruit
    {
    公共字符串Id{get;set;}
    公共字符串名称{get;set;}
    }
    公共级橙色:IFruit
    {
    公共字符串Id{get;set;}
    公共字符串名称{get;set;}
    }
    
    测试
    例如,在同一个会话中抛出InvalidCastException(有效),但在第二个会话中则不起作用

    公共类UnitTest1
    {
    [事实]
    公共异步任务SameSession_Works_和_Throws_InvalidCastException()
    {
    var store=new DocumentStore()
    {
    URL=new[]{”http://192.168.99.100:32772"},
    数据库=“水果”
    }.Initialize();
    使用(var session=store.OpenAsyncSession())
    {
    新苹果
    {
    Id=Guid.NewGuid().ToString(),
    Name=“Elstar”
    };
    wait session.StoreAsync(苹果);
    wait session.saveChangesSync();
    等待Assert.ThrowsAsync(()=>session.LoadAsync(apple.Id));
    }
    }
    [事实]
    公共异步任务不同会话失败()
    {
    var store=new DocumentStore()
    {
    URL=new[]{”http://192.168.99.100:32772"},
    数据库=“水果”
    }.Initialize();
    使用(var session=store.OpenAsyncSession())
    {
    var appleId=“ca5d9fd0-475b-41de-a1ab-57bb1e3ce018”;
    //这个应该坏了,因为…它是个苹果
    //…但它没有-它返回一个橙色
    var orange=await session.LoadAsync(appleId);
    等待Assert.ThrowsAsync(()=>session.LoadAsync(appleId));
    }
    }
    }
    
    .Query.Where(x=>x.Id==Id)
    是一种方法。在Ravendb4.0中,按ID进行的查询直接由封面下的文档存储(而不是索引)处理,因此它的效率与
    Load
    相同


    您的场景的优点是查询的范围仅限于指定的集合。

    好吧,我发现了问题所在,但我