自动扩展odata函数的结果

时间:2018-10-15 14:54:00

标签: asp.net-web-api asp.net-core odata

我定义了一个模仿$ search的odata函数,该函数在最近的核心版本中尚不支持。我想返回核心实体以及扩展的实体,该实体将转换为返回的json值数组中每个Person上的js对象。

我在odata/People/MyNS.Find(text='john', orderby='CreatedOn')?$expand=CurrentWork上尝试了CurrentWork在People上,但是那没用。

关于如何执行此操作的想法?

  // my controller code for the function
  [HttpGet]
  public ActionResult<ICollection<People>> Find([FromODataUri] string text,
        [FromODataUri] string orderBy)
        {
            if (text == null || text.Length == 0)
                return Get().ToList();
            if (orderBy == null || orderBy.Length == 0)
                orderBy = "CreatedOn";
            return _db.People
                .Where(p => p.FirstName.Contains(text)
                    || p.LastName.Contains(text)
                    || p.Nickname.Contains(text))
                .OrderBy(orderBy)
                .Take(5000)
                .ToList();
        }

在不起作用的情况下常规扩展CurrentWork可以很好地工作,例如odata/People?$expand=CurrentWork

2 个答案:

答案 0 :(得分:1)

通过查看Linq查询,它仅获取People数据,而不获取其任何子集合。您应该使用Include来获取子集合以及父实体的数据,如下所示。详细了解如何加载相关实体here

// my controller code for the function
[HttpGet]
public ActionResult<ICollection<People>> Find([FromODataUri] string text,
    [FromODataUri] string orderBy)
{
    if (text == null || text.Length == 0)
        return Get().ToList();
    if (orderBy == null || orderBy.Length == 0)
        orderBy = "CreatedOn";
    return _db.People
        .Where(p => p.FirstName.Contains(text)
            || p.LastName.Contains(text)
            || p.Nickname.Contains(text))
        .Include(p => p.CurrentWork) // I have added this line
        .OrderBy(orderBy)
        .Take(5000)
        .ToList();
}

注意:您仍然需要使用$ expand = CurrentWork作为查询字符串。如果没有此查询字符串,服务器将在向客户端发送响应之前删除子集合。

答案 1 :(得分:0)

这就是我最后想出的。我注意到所包含的实体正在从数据库中提取大量数据,因此我通过具体说明大大降低了这种提取。包括只是拉了一切,我不能直接降低Include,所以我不得不使用Select

    [HttpGet]
    public IOrderedQueryable Find2([FromODataUri] string text,
    [FromODataUri] string orderBy)
    {
        if (orderBy == null || orderBy.Length == 0)
            orderBy = "CreatedOn DESC";
        if (text == null || text.Length == 0)
            return Get().OrderBy(orderBy);
        var r = LikeToRegular(text);
        return _db.People
        .AsNoTracking() // can't use if using lazy loading
        .Select(p => new
        {
            p.FirstName,
            p.LastName,
            p.Nickname,
            p.CreatedOn,
            p.CurrentWork.Title,
            p.CurrentWork.Company.CompanyName
        })
        // Forces local computation, so pulls entire people dataset :-(
        .Where(x => Regex.IsMatch(x.LastName ?? "", r)
        || Regex.IsMatch(x.FirstName ?? "", r, RegexOptions.IgnoreCase)
        || Regex.IsMatch(x.Nickname ?? "", r, RegexOptions.IgnoreCase)
        || Regex.IsMatch($"{x.FirstName} {x.LastName}", r,
                RegexOptions.IgnoreCase))
        .OrderBy(orderBy);
    }
    // Allow some wildcards in the search...
    public static String LikeToRegular(String value)
    {
        return "^" + Regex.Escape(value)
        .Replace("_", ".")
        .Replace("%", ".*") + "$";
    }