entity-framework - 在 REST API 中实现多个参数过滤器的最简洁方法

标签 entity-framework rest asp.net-web-api

我目前正在实现一个 RESTFUL API,它提供与数据库交互的端点。

我想在 API 中实现过滤,但我需要提供一个端点,该端点可以提供一种使用表的所有列对表应用过滤的方法。

我发现了一些模式,例如:

GET /api/ressource?param1=value1,param2=value2...paramN=valueN

param1,param2...param N 是我的表格列和值。

我还发现了另一种模式,其中包括发送表示查询的 JSON 对象。

要过滤某个字段,只需将该字段及其值添加到查询中即可:

GET /app/items
{
  "items": [
    {
      "param1": "value1",
      "param2": "value",
      "param N": "value N"
    }
  ]
}

我正在寻找实现这一目标的最佳实践。

我使用 EF Core 和 ASP.NET Core 来实现此目的。

最佳答案

首先要谨慎过滤所有内容。根据用户的需要设置可用的过滤器,并根据需求进行扩展。编写的代码更少,复杂性更低,数据库端所需的索引更少,性能更好。

也就是说,我对具有大量过滤器的页面使用的方法是使用枚举服务器端,其中我的条件字段将传回其枚举值(数字)以根据请求提供。因此,过滤器字段将包含名称、默认值或适用值以及将输入或选定的值传递回搜索时要使用的枚举值。请求代码创建一个 JSON 对象,其中包含应用的过滤器和 Base64 的它以在请求中发送:

{
  p1: "Jake",
  p2: "8"
}

查询字符串如下所示: .../api/customer/search?filters=XHgde0023GRw....

在服务器端,我提取 Base64 然后将其解析为 Dictionary<string,string>馈送到过滤器解析。例如,假设条件是使用姓名和年龄搜索 child :

// this is the search filter keys, these (int) values are passed to the search client for each filter field.
public enum FilterKeys
{
    None = 0,
    Name,
    Age,
    ParentName
}

public JsonResult Search(string filters)
{
    string filterJson = Encoding.UTF8.GetString(Convert.FromBase64String(filters));
    var filterData = JsonConvert.DeserializeObject<Dictionary<string, string>>(filterJson);

    using (var context = new TestDbContext())
    {
        var query = context.Children.AsQueryable();

        foreach (var filter in filterData)
            query = filterChildren(query, filter.Key, filter.Value);

        var results = query.ToList(); //example fetch.
        // TODO: Get the results, package up view models, and return...
    }
}

private IQueryable<Child> filterChildren(IQueryable<Child> query, string key, string value)
{
    var filterKey = parseFilterKey(key);
    if (filterKey == FilterKeys.None)
        return query;

    switch (filterKey)
    {
        case FilterKeys.Name:
            query = query.Where(x => x.Name == value);
            break;
        case FilterKeys.Age:
            DateTime birthDateStart = DateTime.Today.AddYears((int.Parse(value) + 1) * -1);
            DateTime birthDateEnd = birthDateStart.AddYears(1);
            query = query.Where(x => x.BirthDate <= birthDateEnd && x.BirthDate >= birthDateStart);
            break;
    }
    return query;
}

private FilterKeys parseFilterKey(string key)
{
    FilterKeys filterKey = FilterKeys.None;

    Enum.TryParse(key.Substring(1), out filterKey);
    return filterKey;
}

您可以使用字符串和常量来避免枚举解析,但是我发现枚举是可读的并且使发送的有效负载更加紧凑。上面是一个简化的例子,显然需要错误检查。复杂过滤条件(例如上面的年龄到出生日期)的实现代码更适合作为单独的方法,但它应该给您一些想法。例如,您可以按姓名、和/或年龄、和/或 parent 姓名搜索 child 。

关于entity-framework - 在 REST API 中实现多个参数过滤器的最简洁方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53434725/

相关文章:

ruby-on-rails - 如何使用 curl 查询 restful rails 应用程序?

java - 带有 Java 客户端的服务堆栈

asp.net-web-api - 资源所有者凭据与 JavaScript 和 IdentityServer 一起流动 - 不允许吗?

ssl - .Net 网络 API、SSL + 基本身份验证

c# - 在 Entity Framework 中将 1 映射到 0-1

c# - 使用 LINQ 将三个列表连接成一个会引发异常

security - 如何从 RESTful 服务发送安全 token ?

c# - 仅返回字段时使用 AsNoTracking() 会有所不同吗?

c# - 无法将类型 ApplicationUser 隐式转换为 User

c# - 无法在 Azure 函数中加载程序集或 dll System.Buffers,Version=4.0.2.0