1

我将 WCF 数据服务 5.3.0 与反射数据提供程序一起使用。我的源数据存储在 RavenDB 中,所以我的所有查询都被推迟了。那么,在应用 OData 过滤器之后和结果返回给客户端之前,是否有一些方法可以为我的查​​询调用 .ToList()?

更新:我的 DataModel 属性声明

    public IQueryable<PositionModel> Positions
    {
        get
        {
            using (var session = OLAPDocumentStore.OpenSession())
            {
                return session
                    .Query<ConsolidatedApplicationPosition>()
                    .Select(x => new PositionModel
                                     {
                                         ApplicationId = x.ApplicationId,
                                         CategoryId = x.CategoryId,
                                         ID = x.Id,
                                         Platform = x.Platform,
                                         Position = x.Position,
                                         RegionalCode = x.RegionalCode,
                                         Timestamp = x.Timestamp,
                                         TopListId = x.TopListId
                                     })
                    .AsQueryable();
            }
        }
    }

解决方案请参阅@matt-johnson 答案,并且不要忘记将 [DataMember] 添加到模型中的所有属性

[DataContract, DataServiceKey("Id")]
public class PositionModel
{
    [DataMember]
    public string Id { get; set; }
    [DataMember]
    public string ApplicationId { get; set; }
    [DataMember]
    public string CategoryId { get; set; }
    [DataMember]
    public int Position { get; set; }
    [DataMember]
    public string RegionalCode { get; set; }
    [DataMember]
    public DateTime Timestamp { get; set; }
    [DataMember]
    public string TopListId { get; set; }
}
4

1 回答 1

2

好的,我不得不回忆一下 WCF 数据服务的工作原理。Shawn Wildermuth 有一个很好的示例视频

主要问题是您正在尝试使用Select语句转换查询客户端。当您返回一个IQueryable, 应该直接挂接到 linq 提供程序 - 在这种情况下,是 RavenDB 查询的输出。您可以应用WhereOrderBy过滤,但不能对Select语句进行投影。这打破了查询链。

因此,如果您想从ConsolidatedApplicationPosition数据库中的PositionModel对象投影到要返回到 WCF 数据服务的对象,您将不得不以另一种方式进行。以下是一些选项:

  1. 如果您需要投影的所有字段都已经在源数据中,那么您可以这样做:

    return session.Query<ConsolidatedApplicationPosition>()
                  .AsProjection<PositionModel>();
    

    这里唯一的问题是您的标识符不匹配。Raven 的默认标识符约定是Id(Pascal 大小写),而 WCF 是ID(大写)。您可以通过更改 Raven 的约定来排列它们:

    DocumentStore.Conventions.FindIdentityProperty = x => x.Name == "ID";
    

    或通过使用DataServiceKey属性更改 WCF 的约定:

    [DataContract, DataServiceKey("Id")]
    public class PositionModel
    {
        [DataMember]
        public int Id { get; set; }
    
        ...
    }
    
  2. 如果要保持标识符不匹配,或者要转换更多字段,则无法使用动态索引。相反,您必须创建一个静态索引并使用转换来控制投影:

    public class YourIndex : AbstractIndexCreationTask<ConsolidatedApplicationPosition>
    {
      public YourIndex()
      {
        Map = docs =>
          from doc in docs
          select new
          {
            // You need to map any fields that you might query
            // or sort on through the odata filters.
          };
    
        TransformResults = (database, docs) =>
          from doc in docs
          select new PositionModel
          {
            // if you need integer identifiers in your result,
            // you'll have to split them from the doc key, like this:
            ID = int.Parse(doc.Id.ToString().Split('/')[1]),
    
            // otherwise, just do this:
            ID = doc.Id,
    
            // bring over all of your other fields as well
            Platform = doc.Platform
            ... etc ...
    
         };
      }
    }
    

    建立索引后,您可以像这样查询它:

    return session.Query<PositionModel, YourIndex>();
    

使用任一选项,查询中都没有 select 语句,因此无需执行ToListor AsQueryable。您只是将IQueryableRavenDB linq 提供程序的接口发送到 WCF 数据服务上下文中。

于 2013-03-04T15:37:42.800 回答