Asp.net web api 自动展开odata函数的结果

Asp.net web api 自动展开odata函数的结果,asp.net-web-api,asp.net-core,odata,Asp.net Web Api,Asp.net Core,Odata,我定义了一个odata函数来模拟$search,这在最近的核心版本中还不受支持。我想返回核心实体加上一个扩展实体,该实体将转换为返回的json值数组中每个人的js对象 我尝试了odata/People/MyNS.Find(text='john',orderby='CreatedOn')?$expand=CurrentWork,其中CurrentWork是针对人的,但没有成功 关于如何做到这一点的想法 // my controller code for the function [Http

我定义了一个odata函数来模拟$search,这在最近的核心版本中还不受支持。我想返回核心实体加上一个扩展实体,该实体将转换为返回的json值数组中每个人的js对象

我尝试了
odata/People/MyNS.Find(text='john',orderby='CreatedOn')?$expand=CurrentWork
,其中CurrentWork是针对人的,但没有成功

关于如何做到这一点的想法

  // 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();
        }
//函数的我的控制器代码
[HttpGet]
公共操作结果查找([FromODataUri]字符串文本,
[FromODataUri]字符串排序依据)
{
if(text==null | | text.Length==0)
返回Get().ToList();
if(orderBy==null | | orderBy.Length==0)
orderBy=“CreatedOn”;
返回_db.People
.Where(p=>p.FirstName.Contains(文本)
||p.LastName.Contains(文本)
||p.昵称.包含(文本))
.OrderBy(OrderBy)
.Take(5000)
.ToList();
}

在非函数中定期扩展CurrentWork可以正常工作,例如,
odata/People?$expand=CurrentWork

通过查看Linq查询,它只获取人员数据,而不获取其任何子集合。您应该使用
Include
获取子集合以及父实体的数据,如下所示。阅读有关加载相关实体的更多信息

//函数的我的控制器代码
[HttpGet]
公共操作结果查找([FromODataUri]字符串文本,
[FromODataUri]字符串排序依据)
{
if(text==null | | text.Length==0)
返回Get().ToList();
if(orderBy==null | | orderBy.Length==0)
orderBy=“CreatedOn”;
返回_db.People
.Where(p=>p.FirstName.Contains(文本)
||p.LastName.Contains(文本)
||p.昵称.包含(文本))
.Include(p=>p.CurrentWork)//我添加了这一行
.OrderBy(OrderBy)
.Take(5000)
.ToList();
}

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

通过查看Linq查询,它只获取人员数据,而不获取任何子集合。您应该使用
Include
获取子集合以及父实体的数据,如下所示。阅读有关加载相关实体的更多信息

//函数的我的控制器代码
[HttpGet]
公共操作结果查找([FromODataUri]字符串文本,
[FromODataUri]字符串排序依据)
{
if(text==null | | text.Length==0)
返回Get().ToList();
if(orderBy==null | | orderBy.Length==0)
orderBy=“CreatedOn”;
返回_db.People
.Where(p=>p.FirstName.Contains(文本)
||p.LastName.Contains(文本)
||p.昵称.包含(文本))
.Include(p=>p.CurrentWork)//我添加了这一行
.OrderBy(OrderBy)
.Take(5000)
.ToList();
}

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

下面是我最后的想法。我注意到,包含的实体从数据库中提取了大量数据,因此我通过具体化减少了提取量。Include只是将所有内容都拉了出来,我无法直接减少
Include
,因此我不得不使用
选择

    [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("%", ".*") + "$";
    }

这是我最后想到的。我注意到,包含的实体从数据库中提取了大量数据,因此我通过具体化减少了提取量。Include只是将所有内容都拉了出来,我无法直接减少
Include
,因此我不得不使用
选择

    [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("%", ".*") + "$";
    }

这似乎确实做到了。在阅读了更多的文档之后,我还决定让aspnetcore通过返回IOrderedQueryable、在控制器上设置maxtop、删除跟踪并使用regexs来调用查询。regexs强制在初始获取之后在客户端进行计算,但允许我更容易地使用通配符。对于大型人员数据集来说不是很好,但效果足够好。我的“includes”仍然拉入了太多的数据,但这是另一天的担忧。这似乎确实做到了。在阅读了更多的文档之后,我还决定让aspnetcore通过返回IOrderedQueryable、在控制器上设置maxtop、删除跟踪并使用regexs来调用查询。regexs强制在初始获取之后在客户端进行计算,但允许我更容易地使用通配符。对于大型人员数据集来说不是很好,但效果足够好。我的“includes”仍然拉入了太多的数据,但这是另一天要考虑的问题。请注意,似乎根据您声明函数的方式,您可能会或可能不会返回有效的odata响应,即使您不会得到错误。上面的函数返回一个纯json数组作为无效odata的响应。Vinit的评论似乎是正确的,您需要包含$expand查询参数,以便
include
不仅从数据库中提取数据,而且如果您首先要生成有效的odata响应,还需要将其包含在odata格式的响应中。请注意,看起来,根据您声明函数的方式,您可能会或可能不会返回有效的odata响应,即使您不会得到错误。上面的函数返回一个纯json数组作为无效odata的响应。Vinit的评论似乎是正确的,您需要包含$expand查询参数,以便
include
不仅从数据库中提取数据,而且如果您首先要生成有效的odata响应,还需要将其包含在odata格式的响应中。