无法在 RavenDB 上查询附件

问题描述

我正在尝试查询文档以及 RavendB 上的附件列表。

我有以下对象:

   public class Post
    {
        public string Id { get; set; }
        public string Url { get; set; }
        public Profile Profile { get; set; }
        public DateTime CreatedOn { get; set; }
        [JsonProperty("@Metadata")]
        public Metadata Metadata { get; set; }
    }

    public class Metadata
    {
        [JsonProperty("@attachments")]
        public List<AttachmentName> Attachments { get; set; }
    }

当我尝试执行以下查询时:

return await query.Select(x => new Repository.SummaryPost
            {
                Id = x.Id,CreatedOn = x.CreatedOn,Url = x.Url,AttachmentNames = x.Metadata.Attachments.Select(x => x.Name),Profile = new Repository.SummaryProfile
                {
                    Id = x.Profile.Id,Name = x.Profile.Name,Url = x.Profile.Url,Source = new Repository.SummarySource
                    {
                        Id = x.Profile.source.Id,Name = x.Profile.source.Name,Url = x.Profile.source.Url
                    }
                }
            }).ToListAsync()

它尝试运行以下 RQL:

from 'Posts' as x 
order by CreatedOn desc 
select { 
    Id : id(x),CreatedOn : x.CreatedOn,Url : x.Url,AttachmentNames : x.@Metadata.@attachments.map(function(x){return x.Name;}),Profile : 
    {
        Id:x.Profile.Id,Name:x.Profile.Name,Url:x.Profile.Url,Source:{
            Id:x.Profile.source.Id,Name:x.Profile.source.Name,Url:x.Profile.source.Url
        }
    }
}
limit $p0,$p1

这是无效的,并抛出以下错误

 ---> esprima.ParserException: Line 5: Unexpected token ILLEgal
   at esprima.Scanner.ThrowUnexpectedToken(String message)
   at esprima.Scanner.ScanPunctuator()
   at esprima.JavaScriptParser.NextToken()
   at esprima.JavaScriptParser.ParseLeftHandSideExpressionAllowCall()
   at esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at esprima.JavaScriptParser.ParseUpdateExpression()
   at esprima.JavaScriptParser.ParseUnaryExpression()
   at esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at esprima.JavaScriptParser.ParseExponentiationExpression()
   at esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at esprima.JavaScriptParser.ParseBinaryExpression()
   at esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at esprima.JavaScriptParser.ParseConditionalExpression()
   at esprima.JavaScriptParser.ParseAssignmentExpression()
   at esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at esprima.JavaScriptParser.ParSEObjectProperty(Token hasProto)
   at esprima.JavaScriptParser.ParSEObjectinitializer()
   at esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at esprima.JavaScriptParser.ParsePrimaryExpression()
   at esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at esprima.JavaScriptParser.ParseLeftHandSideExpressionAllowCall()
   at esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at esprima.JavaScriptParser.ParseUpdateExpression()
   at esprima.JavaScriptParser.ParseUnaryExpression()
   at esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at esprima.JavaScriptParser.ParseExponentiationExpression()
   at esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at esprima.JavaScriptParser.ParseBinaryExpression()
   at esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at esprima.JavaScriptParser.ParseConditionalExpression()
   at esprima.JavaScriptParser.ParseAssignmentExpression()
   at esprima.JavaScriptParser.IsolateCoverGrammar[T](Func`1 parseFunction)
   at esprima.JavaScriptParser.ParseExpression()
   at esprima.JavaScriptParser.ParseReturnStatement()
   at esprima.JavaScriptParser.ParseStatement()
   at esprima.JavaScriptParser.ParseStatementListItem()
   at esprima.JavaScriptParser.ParseScript(Boolean strict)
   at Raven.Server.Documents.Queries.QueryMetadata.HandleSelectFunctionBody(BlittableJsonReaderObject parameters) in C:\Builds\RavendB-Stable-5.1\51018\src\Raven.Server\Documents\Queries\QueryMetadata.cs:line 601

这是由于 x.@Metadata.@attachments,如果我在没有 Raven Studio 元数据的情况下运行相同的查询,它运行没有问题。

我想知道我是否遗漏了什么,或者是否有适当的方法来实现这一点。

解决方法

经过一些尝试和错误尝试后,我可以弄清楚如何正确地做到这一点。

首先,不需要使用那些 JsonProperty 表示法。其次,要正确查询元数据,我们需要使用 RQL 中的 getMetadata(x),并且要生成该查询,我们需要修改该 LINQ 以使用 RavenQuery.Metadata(x)。像这样:

 return await query.Select(x => new Repository.SummaryPost
            {
                Id = x.Id,CreatedOn = x.CreatedOn,Url = x.Url,Metadata = RavenQuery.Metadata(x)["@attachments"],Profile = new Repository.SummaryProfile
                {
                    Id = x.Profile.Id,Name = x.Profile.Name,Url = x.Profile.Url,Source = new Repository.SummarySource
                    {
                        Id = x.Profile.Source.Id,Name = x.Profile.Source.Name,Url = x.Profile.Source.Url
                    }
                }
            }).ToListAsync();

这将生成以下 RQL:

from 'Posts' as x 
order by CreatedOn desc 
select { 
    Id : id(x),CreatedOn : x.CreatedOn,Url : x.Url,Metadata : getMetadata(x)["@attachments"],Profile : {
        Id:x.Profile.Id,Name:x.Profile.Name,Url:x.Profile.Url,Source:{
            Id:x.Profile.Source.Id,Name:x.Profile.Source.Name,Url:x.Profile.Source.Url
            }
    }
    
} 
limit $p0,$p1

获取文档列表和附件列表。

通过在 LINQ 查询中添加以下行,我们甚至可以更具体地只查询附件名称:

AttachmentNames = ((IEnumerable<AttachmentName>) RavenQuery.Metadata(x)["@attachments"]).Select(x => x.Name)

它将为 AttachmentNames 字段生成以下 RQL:

AttachmentNames : getMetadata(x)["@attachments"].map(function(x){return x.Name;})

仅查询名称。