OData 8.0中如何将ApplyTo结果转换为IQueryable<T>?
问题原因
当使用$select或$expand时,OData会生成Microsoft.AspNetCore.OData.Query.Wrapper.SelectSome包装类来封装仅包含所选属性的结果,此时返回的IQueryable元素类型不再是Customer,直接转换或Cast<Customer>会因类型不匹配抛出异常。
解决方案
方案1:禁用$select和$expand(强制返回完整实体)
如果业务上不需要支持部分字段查询和关联展开,可以在验证时禁用这两个查询选项,确保ApplyTo始终返回IQueryable<Customer>:
IQueryable<Customer> customers = _customerRepository.GetAll(); request.Input.Validate(new ODataValidationSettings() { AllowedFunctions = AllowedFunctions.AllMathFunctions, // 移除Select和Expand的权限 AllowedQueryOptions = AllowedQueryOptions.All & ~AllowedQueryOptions.Select & ~AllowedQueryOptions.Expand }); // 此时data仍是IQueryable<Customer>,转换正常 IQueryable<Customer> dataRdy = request.Input.ApplyTo(customers, new ODataQuerySettings()) as IQueryable<Customer>; List<Customer> dataList = dataRdy.ToList();
优点:实现简单,不改变原有业务逻辑;缺点:无法支持部分字段查询和关联展开。
方案2:手动映射包装类到Customer(支持$select/$expand)
如果需要保留$select和$expand功能,可以先将结果转为动态类型,再映射回Customer(缺失的属性会为默认值):
IQueryable<Customer> customers = _customerRepository.GetAll(); request.Input.Validate(new ODataValidationSettings() { AllowedFunctions = AllowedFunctions.AllMathFunctions }); IQueryable data = request.Input.ApplyTo(customers, new ODataQuerySettings()); // 先转为动态类型枚举,再映射到Customer var dataList = data.Cast<dynamic>() .Select(item => new Customer { Id = item.Id, Name = item.Name, // 根据业务需求添加需要映射的属性,或用反射自动复制 }) .ToList();
如果属性较多,可使用反射简化映射:
var dataList = data.Cast<dynamic>() .Select(item => { Customer customer = new Customer(); var itemType = item.GetType(); foreach (var customerProp in typeof(Customer).GetProperties()) { var itemProp = itemType.GetProperty(customerProp.Name); if (itemProp != null) { customerProp.SetValue(customer, itemProp.GetValue(item)); } } return customer; }) .ToList();
优点:支持OData的所有查询功能;缺点:需要手动处理属性映射,反射会带来轻微性能损耗。
方案3:手动拆分OData查询选项(精准控制返回类型)
如果需要更精准的控制,可以拆分ODataQueryOptions的各个部分,手动应用查询并确保返回IQueryable<Customer>:
IQueryable<Customer> customers = _customerRepository.GetAll(); request.Input.Validate(new ODataValidationSettings() { AllowedFunctions = AllowedFunctions.AllMathFunctions }); // 应用Select/Expand(若存在) if (request.Input.SelectExpand != null) { customers = request.Input.SelectExpand.ApplyTo(customers, new ODataQuerySettings()) as IQueryable<Customer>; } // 应用Filter if (request.Input.Filter != null) { customers = request.Input.Filter.ApplyTo(customers, new ODataQuerySettings()) as IQueryable<Customer>; } // 应用OrderBy if (request.Input.OrderBy != null) { customers = request.Input.OrderBy.ApplyTo(customers, new ODataQuerySettings()) as IQueryable<Customer>; } // 应用Skip/Top if (request.Input.Skip != null) { customers = request.Input.Skip.ApplyTo(customers, new ODataQuerySettings()) as IQueryable<Customer>; } if (request.Input.Top != null) { customers = request.Input.Top.ApplyTo(customers, new ODataQuerySettings()) as IQueryable<Customer>; } List<Customer> dataList = customers.ToList();
优点:完全控制查询流程,确保返回类型正确;缺点:需要手动处理所有OData查询选项,代码量较大。
内容的提问来源于stack exchange,提问作者pietro
相关产品推荐
相关产品推荐

