2017-02-28 66 views
1

我已经定义了自己的结构,它代表DateTimeTimeZoneInfo,所以我可以在保留有关时区的信息的同时使用UTC时间。Web Api自定义类型的OData查询

我想用OData查询获得这些对象,但是当我尝试在此类属性上使用$orderby时失败。当我询问$orderBy=Timestamp/Value/UniversalTime时我能得到结果,但我只想使用$orderBy=Timestamp

有没有可能使用此类型订购集合?

public struct DateTimeWithZone : IComparable<DateTime>, IComparable<DateTimeWithZone>, IFormattable 
{ 
    private readonly DateTime _utcDateTime; 
    private readonly TimeZoneInfo _timeZone; 

    public DateTimeWithZone(DateTime dateTime, TimeZoneInfo timeZone) 
    { 
     if (timeZone == null) 
     { 
      throw new NoNullAllowedException(nameof(timeZone)); 
     } 

     _utcDateTime = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc); 
     _timeZone = timeZone; 
    } 


    ... 
} 

有了这样定义的模型:

public class ClientViewModel 
{ 
    public string Name { get; set; } 
    public DateTimeWithZone? Timestamp { get; set; } 
} 

,这是它是如何使用:

public IHttpActionResult GetAll(ODataQueryOptions<ClientViewModel> options) 
    { 
     var fromService = _clientsClient.GetAllClients().MapTo<ClientViewModel>(MappingStrategy).AsQueryable(); 
     var totalCount = fromService.Count(); 
     var results = options.ApplyTo(fromService); // <-- Fails here 

     return Ok(new PageResult<ClientViewModel>(
      results as IEnumerable<ClientViewModel>, 
      Request.ODataProperties().NextLink, 
      totalCount)); 
    } 

The $orderby expression must evaluate to a single value of primitive type.

回答

0

失败,我们不得不应对复杂的类型做了一些类似的问题,排序。也许这可以在你的场景中提供帮助。在我们的情况下(这是不是100%相同),我们使用一个两个阶段方法:

  1. 重写ODataQueryOptions
  2. 分离extneral模型(ODATA)和(在我们的情况下的EntityFramework)内部模型

重写ODataQueryOptions

您提到的格式$orderBy=Timestamp/Value/UniversalTime被接受并由ODATA正确处理。因此,您可以通过提取$orderby值并重新插入工作格式来重写该值。

我描述了如何在我的文章Modifying ODataQueryOptions on the fly(包括完整代码)中执行此操作的两种方式,它们通过构建新的Uri来使现有选项重新创建新选项。在你的情况下,你会从$orderBy=Timestamp提取时间戳,并重新插入与$orderBy=Timestamp/Value/UniversalTime一样。

分离外部和内部模型

此外,我们使用了两种型号为面向公众的API和内部/持久层。在内部我们使用了不同的属性,我们将其分组为一个导航属性(只存在于公共端)。通过这种方法,用户可以通过$expand=VirtualNavigationProperty/TimeZoneInfo$orderby=...指定一个选项。在内部,您不必使用复杂的数据类型,但请继续使用已存储该信息的DateTimeOffset。我描述了在下面的帖子这种分离和映射虚拟导航性能:

根据你的问题应该足以改写控制器中的查询选项,你确实提到(格式稍长一些)$orderby格式已经按预期工作,您只需要更方便的查询语法。

Regards,Ronald