将 ODATA $expand 查询选项与 WebAPI 和 ViewModel 一起使用

Posted

技术标签:

【中文标题】将 ODATA $expand 查询选项与 WebAPI 和 ViewModel 一起使用【英文标题】:Using the ODATA $expand query option with WebAPI and a ViewModel 【发布时间】:2013-11-20 01:03:19 【问题描述】:

This question 非常相似,但没有给我我需要的东西。

我正在使用 Entity Framework 6。我的数据库有两个表,Customers 和 CustomerTypes。我为每个创建了一个 ViewModel。客户可以有一个类型:

public class Customer

    public int CustomerID  get; set; 
    public string CustomerName  get; set; 
    public CustomerTypeViewModel CustomerType  get; set; 


public class CustomerTypeViewModel

    public int CustomerTypeID  get; set; 
    public string CustomerTypeDescription  get; set; 

我有一个客户控制器,它公开了一个返回类型为 IQueryable 的 odata 操作方法:

[HttpPost, Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
    public IQueryable<CustomerViewModel> GetCustomersMatchingCriteria([FromBody]ODataActionParameters parameters)
    
        var criteria = (CustomerMassUpdateCriteriaViewModel)parameters["Criteria"];

        return Common.Customers.GetCustomerMassUpdateCriteriaResults(criteria,
            ConfigurationManager.AppSettings["CLIENT_ID"]).Select(
            c => new CustomerViewModel()
            
                CustomerID = c.CustomerID,
                CustomerName = c.CustomerName,
                CustomerType = new CustomerTypeViewModel() 
                
                    CustomerTypeDescription = c.CustomerType.CustomerTypeDescription
                
            );
    

Common.Customers.GetCustomerMassUpdateCriteriaResults 方法只返回一个 Customer 的 IQueryable,它是实际的实体。

问题是,当使用以下查询字符串选项调用此控制器方法时:

$expand=CustomerType
$select=CustomerID,CustomerName,CustomerType/CustomerTypeDescription

抛出此异常:

“ObjectContent`1”类型未能序列化内容类型的响应正文 '应用程序/json; charset=utf-8'.","type":"System.InvalidOperationException"

DbIsNullExpression 的参数必须引用原语、枚举或引用类型。

从 $select 列表中删除 $expand 选项和关联的 CustomerType/CustomerTypeDescription 属性不会产生错误。

我觉得我在这里遗漏了一些明显的东西。有什么想法吗?

第一次编辑:

通过 ToList() 扩展方法枚举结果并返回 IEnumerable 而不是 IQueryable 成功扩展了 CustomerType 导航属性,但我的 ODATA $select 列表不再在数据库级别受到尊重。这不是违背了使用 ODATA 的目的吗?

【问题讨论】:

您最终找到解决方案了吗?我还在努力解决这个问题。 @Josh,不,我没有。我最终做的是根据我的需要创建一个更具体的视图模型(或 dto 或任何你的情况)。我需要访问嵌套属性的属性,如果使用“$expand”会很好,但我最终只是将该属性粘贴在我的主视图模型上并放弃了“$expand”选项和嵌套属性。因此,我不得不在架构上重新考虑一些事情,我不太喜欢这个解决方案,但显然这是我目前唯一的选择。 【参考方案1】:

例外:

“ObjectContent`1”类型未能序列化响应正文 内容类型'应用程序/json; charset=utf-8'.","type":"System.InvalidOperationException"

据我所知,这是由于请求如何达到 OData 格式。请求应到达 OData 路由以进行格式化。如果您可以将 GlobalConfiguration.Configuration.EnableOData() 移到 global.asax 中的 RouteConfig.RegisterRoutesWebApiConfig.Register 之前会有所帮助。

【讨论】:

据我了解,Queryable(AllowedQueryOptions = AllowedQueryOptions.All) 属性应该在更本地的级别上做同样的事情,但我确实尝试过你的建议,发现 EnableOData()方法不是 GlobalConfiguration.Configuration 的成员。也许它在 WebAPI 5.0 中不可用?

以上是关于将 ODATA $expand 查询选项与 WebAPI 和 ViewModel 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

odata - 结合 $expand 和 $select

使用 $expand 时的 Web API OData 媒体类型格式化程序

WebAPI Odata 在无类型实体上应用查询选项

OData $filter 与 $expand 中的项目

如何在 C# 中拆分 OData 多级展开查询字符串?

ASP.NET C# OData 服务 + 导航属性 + $expand = null。我错过了啥?