在计算属性上使用包含时,OData v4筛选器查询失败

本文关键字:v4 OData 筛选 失败 查询 包含时 属性 计算 | 更新日期: 2023-09-27 18:29:19

所以我有一个代码优先的EF 6层,它的Contact类为:

public class Contact
{
    [Key]
    public int Id { get; set; }
    [MaxLength(50)]
    public string Prefix { get; set; }
    [MaxLength(50)]
    public string Suffix { get; set; }
    [MaxLength(50)]
    public string FirstName { get; set; }
    [MaxLength(50)]
    public string MiddleName { get; set; }
    [MaxLength(50)]
    public string LastName { get; set; }
    [NotMapped]
    [DisplayName("Full Name")]
    public string FullName
    {
        get
        {
            string tempName =
                (!string.IsNullOrEmpty(Prefix) ? Prefix + " " : "") +
                (!string.IsNullOrEmpty(FirstName) ? FirstName + " " : "") +
                (!string.IsNullOrEmpty(MiddleName) ? MiddleName + " " : "") +
                (!string.IsNullOrEmpty(LastName) ? LastName + " " : "") +
                (!string.IsNullOrEmpty(Suffix) ? Suffix + " " : "");
            return tempName.Trim();
        }
    }
    [MaxLength(50)]
    public string JobTitle { get; set; }
    public bool? Primary { get; set; }
    public bool? Inactive { get; set; }
    public int? Customer_Id { get; set; }
    [ForeignKey("Customer_Id")]
    public virtual Customer Customer { get; set; }
    public virtual ICollection<Email> Emails { get; set; }
    public virtual ICollection<Address> Addresses { get; set; }
    public virtual ICollection<PhoneNumber> PhoneNumbers { get; set; }
    public virtual ICollection<Note> Notes { get; set; }
}

我运行了一个ASP.NET Web API 2服务,该服务提供联系人列表,但当我执行$filter=contains(tolower(FullName),tolower('smith'))的OData查询时,我会得到BadRequest响应。我在WebAPI get方法中验证了它成功地从数据库中获取结果,但它发回了BadRequest错误。

它肯定与FullName字段有关,要么是计算字段,要么是因为它具有NotMapped属性。当我将OData查询更改为$filter=contains(tolower(LastName),tolower('smith'))时,它可以正常工作。我还尝试在查询中使用显示名称"FullName"而不是"FullName",但这也不起作用。

我需要做些什么来让OData在计算或未映射的字段中表现得很好吗?

在计算属性上使用包含时,OData v4筛选器查询失败

在ContactsController上实现一个OData函数,该函数接受一个字符串进行比较,并返回过滤后的Contacts集。类似于:

    [HttpGet]
    [ODataRoute("Contacts/Default.FullNameContains(value={value})")]
    public IHttpActionResult FullNameContains(string value)
    {
        value = value.ToLower();
        return Ok(db.Contacts.ToList().Where(c => c.FullName.Contains(value)));
    }

因为FullName是计算出来的,所以函数必须在内存中执行过滤。

@lencharest的答案将给出正确的结果,但请记住,为了执行筛选,您将把所有数据拉入内存。如果你有100个联系人,那没什么大不了的,但如果你有很多联系人呢?

我会在DB中创建一个包含FullName逻辑的视图。然后,将此视图作为实体公开。然后,过滤可以在数据库中进行,并且您可以拥有一个完全可查询的实体。

更新:再仔细考虑一下,一个更好的方法是在表中为FullName计算一列。假设您最终可能需要支持其他动词(POST、PATCH等…),那么在表中有完整的实体定义将使事情向前发展。通过实现OData函数,您基本上放弃了可查询的OData模型。它们有自己的位置,但通常用于复杂的多实体操作,而不是在基本实体的单个属性上实现过滤器。