在URI参数是可选的情况下,WebAPI中的Linq-To实体基于父字段查询子实体



我有两个表Schedule和ScheduleItems,它们具有一对多关系

时间表:

  • ScheduleID(Guid)
  • ChannelID(Guid)
  • ScheduleType(字符串)
  • IsComplete(布尔)

日程项目:

  • ScheduleItemID(Guid)
  • ScheduleID(Guid)
  • 标题(字符串)
  • 计划时间(日期时间)
  • ContentType(字符串)

从我的计划项目的webAPI控制器,我希望返回基于URL参数的查询结果,我还希望API是灵活的,因为有些参数是可选的。

因此,在我的ScheduleItems API控制器中,我认为(危险的)我可以根据URI中存在的参数来构建查询。

我的ScheduleItem控制器获取操作:(我认为我可能会做什么)

public async Task<IEnumerable<ScheduleItem>> GetScheduleItems()
    {
        var query = _repository.Get(); // returns IQueryable<ScheduleItem>
        query = query.OrderByDescending(si => si.ScheduledTime);
        var parameters = this.ActionContext.Request.GetQueryNameValuePairs();
        if (parameters != null)
        {
            foreach (var p in parameters)
            {
                if (p.Key.Equals("channelID", StringComparison.OrdinalIgnoreCase))
                {
                    Guid channelID = Guid.Parse(p.Value);
                    query = query.Where(si => si.Schedule.ChannelID.Equals(channelID));
                }
                if (p.Key.Equals("parentScheduleType", StringComparison.OrdinalIgnoreCase))
                {
                    query = query.Where(si => si.Schedule.Type.Equals(p.Value, StringComparison.OrdinalIgnoreCase));
                }
                if (p.Key.Equals("titleSearchTerm", StringComparison.OrdinalIgnoreCase))
                {
                    query = query.Where(si => si.Title.Contains(p.Value));
                }
                if (p.Key.Equals("contentType", StringComparison.OrdinalIgnoreCase))
                {
                    query = query.Where(si => si.ContentType.Equals(p.Value, StringComparison.OrdinalIgnoreCase));
                }
                if (p.Key.Equals("isComplete", StringComparison.OrdinalIgnoreCase))
                {
                    bool isComplete = bool.Parse(p.Value);
                    query = query.Where(si => si.ScheduleMetadata.IsAsRun.Equals(isComplete));
                }
                if (p.Key.Equals("take", StringComparison.OrdinalIgnoreCase))
                {
                    int count = int.Parse(p.Value);
                    query = query.Take(count);
                }
            }
        }
        var result = await query.ToListAsync();
        return result.AsEnumerable();
    }

尽管这确实返回了一些所需的结果,但与直接在数据库上运行等效的SQL查询相比,它不会返回相同数量的结果。

很明显,我在这里偏离了轨道。

我曾考虑放弃这一点,并为每个可能的查询参数变化编写一个控制器操作,但当考虑到这一点时,我意识到我将创建大量的控制器操作。我觉得必须有一种更好的方法来获得我想要的东西,而不需要写那么多控制器动作。

实现这一目标的最佳方式是什么?

注意:我不能在控制器端使用OData查询,因为这破坏了客户端的自定义JSon.NET去串行化。

如果您期望逻辑AND逻辑,那么这个想法通常应该有效。但是,"take"可能不是parameters中的最后一个项目。否则,它可能会显著更改预期结果,因为当结果集大于所取项目的数量时,它可能删除项目。

解决这个问题所需要做的就是将Take()的逻辑从循环中取出,以确保它最后完成。

最新更新