在WebApi2下使用OData v4寻找在一对多导航属性上执行$ orderby的方法。例如,一个经典的联系和地址场景,其中有一对多。
public class Contact
{
public int ContactId { get; set; }
public String FirstName { get; set; }
public virtual ICollection<ContactAddress> Addresses { get; set; }
}
public class ContactAddress
{
public int ContactAddressId { get; set; }
public int ContactId { get; set; }
public virtual Contact Contact { get; set; }
public String AddressOne { get; set; }
public String StateCode { get; set; }
public bool IsPreferred { get; set; }
public String Type { get; set; }
public bool IsActive { get; set; }
}
我们希望支持组合查询,其中可能包括按首选地址StateCode等排序
我意识到以下内容不起作用,因为它不会在单个值/对象中终止:
http://localhost:49380/odata/ODataContacts?$filter=LastName eq 'Smith'&$expand=Addresses&$orderby=Addresses/StateCode
但我想要了解的是解决这个问题的方法是什么。这是一个基本的情景。在直接的LINQ世界中,很容易构建一个表达式,它将对地址进行适当的子过滤以允许这种情况。但是,我希望避免特殊情况,因为我们试图通过OData URL /过滤器和orderby约定来支持简单的查询组合。
理想的是:
http://localhost:49380/odata/ODataContacts?$filter=LastName eq 'Smith'&$expand=Addresses&$orderby=Addresses($filter=IsPreferred eq true)/StateCode
但这似乎并不支持,至少在OData4中,因为它在WebApi中。
我考虑了一个自定义函数,并且每个规范都应该在$ orderby表达式中支持。但是偶然发现了如何实现这一点。假设是这样的:
http://localhost:49380/odata/ODataContacts?$filter=LastName eq 'Smith'&$expand=Addresses&$orderby=ContactService.PreferredAddress(ContactId=$it.ContactId)/StateCode
我对此并没有成功,并且让我感到震惊的是,无论如何构建服务器端执行的查询表达式都“为时已晚”,因为它实际上只是对另一个端点的调用。
我还偶然发现了一些ModelBinding函数,其中许多函数采用lambda表达式,这似乎很有希望。例如:
builder.EntitySet<Contact>("ODataContacts")
.HasOptionalBinding<ContactAddress>(c => c.Addresses.FirstOrDefault(a => a.IsPreferred), "PreferredAddress");
只有我不清楚我需要在实际的实体或控制器上做什么才能使这一切正常。我收到运行时异常,因为PreferredAddress并不存在于任何地方。但看起来这种方法可能效果最好吗?
我可以使用DTO / Queryable方法处理这些问题,但这看起来真的很不幸,而且还有很多额外的工作。
这个问题有实用的方法吗?