我们目前正在尝试使用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的情况下解决这个问题:
提前致谢!
答案 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