RavenDB - 流索引查询导致异常

时间:2015-09-22 07:02:41

标签: c# .net ravendb

我们目前正在尝试使用Task<IAsyncEnumerator<StreamResult<T>>> StreamAsync<T>(IQueryable<T> query, CancellationToken token = null),遇到一些问题。

我们的文档类似于:

public class Entity
{
    public string Id { get; set; }

    public DateTime Created { get; set; }

    public Geolocation Geolocation { get; set; }

    public string Description { get; set; }

    public IList<string> SubEntities { get; set; }

    public Entity()
    {
      this.Id = Guid.NewGuid().ToString();
      this.Created = DateTime.UtcNow;
    }
}

在组合中我们有一个视图模型,它也是模型索引:

public class EntityViewModel
{
    public string Id { get; set; }

    public DateTime Created { get; set; }

    public Geolocation Geolocation { get; set; }

    public string Description { get; set; }

    public IList<SubEntity> SubEntities { get; set; }
}

当然,索引(继承自viewmodel的resulttype)能够正确映射和输出SubEntities,同时允许添加诸如全文等的搜索功能。

public class EntityWithSubentitiesIndex : AbstractIndexCreationTask<Entity, EntityWithSubentitiesIndex.Result>
{
    public class Result : EntityViewModel
    {
         public string Fulltext { get; set; }
    }

    public EntityWithSubentitiesIndex ()
    {
        Map = entities => from entity in entities
                select new
                {
                    Id = entity.Id,
                    Created = entity.Created,
                    Geolocation = entity.Geolocation,
                    SubEntities = entity.SubEntities.Select(x => LoadDocument<SubEntity>(x)),
                    Fulltext = new[]
                    {
                        entity.Description
                    }.Concat(entity.SubEntities.Select(x => LoadDocument<SubEntity>(x).Name)),
                    __ = SpatialGenerate("__geolokation", entity.Geolocation.Lat, entity.Geolocation.Lon)
                };

            Index(x => x.Created.Date, FieldIndexing.Analyzed);
            Index(x => x.Fulltext, FieldIndexing.Analyzed);
            Spatial("__geolokation", x => x.Cartesian.BoundingBoxIndex());
        }
}

最后我们这样查询:

var query = _ravenSession.Query<EntityWithSubentitiesIndex.Result, EntityWithSubentitiesIndex>()
                .Customize(c =>
                {
                    if (filter.Boundary == null) return;

                    var wkt = filter.Boundary.GenerateWkt().Result;
                    if (!string.IsNullOrWhiteSpace(wkt))
                    {
                        c.RelatesToShape("__geolokation", wkt, SpatialRelation.Within);
                    }
                })
                .AsQueryable();

// (...) and several other filters here, removed for clarity

var enumerator = await _ravenSession.Advanced.StreamAsync(query);

var list = new List<EntityViewModel>(); 
while (await enumerator.MoveNextAsync())
{
    list.Add(enumerator.Current.Document);
}

这样做时我们会遇到以下异常:

  

System.InvalidOperationException:查询结果类型为“实体”   但是你希望得到“结果”类型的结果。如果你想   返回一个投影,你应该使用   .ProjectFromIndexFieldsInto()(用于查询)或   .SelectFields()(对于DocumentQuery)在调用之前   .ToList()。

根据文档,Streaming API应支持通过索引进行流式传输,并立即通过IQueryable进行查询。

如何在仍然使用索引和流API的情况下解决这个问题:

  1. 防止必须翻阅正常查询,以解决默认的pagesize
  2. 在查询时防止必须一次加载子实体
  3. 提前致谢!

2 个答案:

答案 0 :(得分:1)

尝试使用:

.As<Entity>()
查询中的

(或.OfType<Entity>())。这应该在常规流中起作用。

这是一个使用“TestIndex”的简单流式查询,它是实体Test的索引,我使用TestIndex.Result看起来像您的查询。 请注意,这实际上不是查询将返回的内容,它只是存在,因此您可以编写类型化查询(即。.Where(x => x.SomethingMapped == something)

var queryable = session.Query<TestIndex.Result, TestIndex>()
                        .Customize(c =>
                        {
                            //do stuff
                        })
                        .As<Test>();

var enumerator = session.Advanced.Stream(queryable);

while (enumerator.MoveNext())
{
    var entity = enumerator.Current.Document;
}

如果您想要从索引中检索值而不是要索引的实际实体,则必须将这些值存储为字段,然后将它们投影到与您的映射属性匹配的“视图模型”中。这可以通过在查询中使用.ProjectFromIndexFieldsInto<T>()来完成。索引中的所有存储字段都将映射到您指定的模型。

希望这有帮助(并且有意义)!

编辑:对我来说,更新了一个与ProjectFromIndexFieldsInto<T>()一起使用的Streaming API的工作示例,它返回了超过128条记录。

using (var session = store.OpenAsyncSession())
{
    var queryable = session.Query<Customers_ByName.QueryModel, Customers_ByName>()
        .Customize(c =>
        {
            //just to do some customization to look more like OP's query
            c.RandomOrdering();
        })
        .ProjectFromIndexFieldsInto<CustomerViewModel>();

    var enumerator = await session.Advanced.StreamAsync(queryable);

    var customerViewModels = new List<CustomerViewModel>();
    while (await enumerator.MoveNextAsync())
    {
        customerViewModels.Add(enumerator.Current.Document);
    }

    Console.WriteLine(customerViewModels.Count); //in my case 504
}

以上代码对我很有用。索引有一个映射的属性(名称),并存储该属性。这是运行最新的稳定版本(3.0.3800)。

答案 1 :(得分:0)

@ @ nicolai-heilbuth在对@ jens-pettersson的回答的评论中指出,从版本3开始,它似乎是RavenDB客户端库中的一个错误。

此处提交的错误报告:http://issues.hibernatingrhinos.com/issue/RavenDB-3916