在RavenDB中将文档展平为视图的最简单方法

5

以下是给定的类:

public class Lookup
{
    public string Code { get; set; }
    public string Name { get; set; }
}

public class DocA
{
    public string Id { get; set; }
    public string Name { get; set; }
    public Lookup Currency { get; set; }
}

public class ViewA // Simply a flattened version of the doc
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string CurrencyName { get; set; } // View just gets the name of the currency
}

我可以创建一个索引,让客户端可以按以下方式查询视图:
public class A_View : AbstractIndexCreationTask<DocA, ViewA>
{
    public A_View()
    {
        Map = docs => from doc in docs
                      select new ViewA
                      {
                          Id = doc.Id,
                          Name = doc.Name,
                          CurrencyName = doc.Currency.Name
                      };

        Reduce = results => from result in results
                      group on new ViewA
                      {
                          Id = result.Id,
                          Name = result.Name,
                          CurrencyName = result.CurrencyName
                      } into g
                      select new ViewA
                      {
                          Id = g.Key.Id,
                          Name = g.Key.Name,
                          CurrencyName = g.Key.CurrencyName
                      };
    }
}

这种方法可以达到预期效果,将数据转换为客户端应用所需的结构形式。然而,这种方式过于冗长,维护起来非常困难,构建冗余对象的效率可能也不高。 是否有更简单的方法,可以在给定文档集(DocA)的情况下创建具有所需结构(ViewA)的索引呢? 更多信息: 问题似乎在于为了让索引按照转换后的结构(ViewA)保存数据,我们必须进行Reduce操作。Reduce必须包含GROUP ON和SELECT才能按预期工作,所以下面两种写法无效:
        Reduce = results => from result in results
                      group on new ViewA
                      {
                          Id = result.Id,
                          Name = result.Name,
                          CurrencyName = result.CurrencyName
                      } into g
                      select g.Key;

这将产生以下结果:System.InvalidOperationException: 变量初始化器select必须具有带有对象创建表达式的lambda表达式。
显然,我们需要使用 'select new'。
无效的REDUCE子句2:
        Reduce = results => from result in results
                      select new ViewA
                      {
                          Id = result.Id,
                          Name = result.Name,
                          CurrencyName = result.CurrencyName
                      };

这会产生一个异常:System.InvalidCastException: 无法将类型为 'ICSharpCode.NRefactory.Ast.IdentifierExpression' 的对象强制转换为类型 'ICSharpCode.NRefactory.Ast.InvocationExpression'。

显然,我们还需要在“group on new”上进行处理。

感谢您所提供的任何帮助。

(注意:从构造函数调用中删除类型(ViewA)对上述内容没有影响)

使用正确方法更新

如下面答案中提到的Daniel的博客所概述的,这是此示例的正确方法:

public class A_View : AbstractIndexCreationTask<DocA, ViewA>
{
    public A_View()
    {
        Map = docs => from doc in docs
                      select new ViewA
                      {
                          Id = doc.Id,
                          Name = doc.Name,
                          CurrencyName = doc.Currency.Name
                      };

        // Top-level properties on ViewA that match those on DocA
        // do not need to be stored in the index.
        Store(x => x.CurrencyName, FieldStorage.Yes);
    }
}

谢谢@Phill。我不知道这里原来的答案发生了什么...... - Phil Degenhardt
1个回答

4

一种解决方案是,在Map中将其扁平化,并配置索引,仅存储在DocA中不存在的属性。

public class A_View : AbstractIndexCreationTask<DocA, ViewA>
{
    public A_View()
    {
        Map = docs => from doc in docs
                      select new ViewA
                      {
                          Id = doc.Id,
                          Name = doc.Name,
                          CurrencyName = doc.Currency.Name
                      };

        // Top-level properties on ViewA that match those on DocA
        // do not need to be stored in the index.
        Store(x => x.CurrencyName, FieldStorage.Yes);
    }
}

我想提醒大家一下,如果你想使用索引进行查询并获取所查询的原始实体,可以这样做:DocumentSession.Query<ViewA, A_View>().Where(x => x.CurrencyName == "EUR").As<DocA>().First();参考链接 - Jeroen Pelgrims

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接