在 URI 参数可选的情况下,WebAPI 中的 Linq To Entities 基于 parent 字段查询 child 个实体
Linq To Entities in WebAPI query child entities based on parent fields in the case where URI parameters are optional
我有两个表 Schedule 和 ScheduleItems 具有 one-to-many 关系
日程安排:
- 计划 ID(向导)
- 频道 ID(向导)
- 计划类型(字符串)
- 完成(布尔值)
计划项目:
- ScheduleItemID (Guid)
- 计划 ID (Guid)
- 标题(字符串)
- 预定时间(日期时间)
- 内容类型(字符串)
从我的 webAPI 计划项目控制器我想 return 基于 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();
}
虽然这确实 return 了一些预期的结果,但与 运行 等效的 SQL 直接查询相比,它return 的结果数量不同数据库。
显然我在这里偏离了轨道。
我考虑过放弃这个并为每个可能的查询参数变体编写一个控制器操作,但是在考虑这个时我意识到我会创建大量的控制器操作。我觉得必须有更好的方法来获得我想要的东西而不用写那么多控制器动作。
实现此目标的最佳方法是什么?
注意:我无法在控制器端使用 OData 查询,因为这破坏了客户端的自定义 JSon.NET de-serialising。
如果您期望符合逻辑 AND 逻辑,那么这个想法通常应该可行。但是,"take"
可能不是 parameters
中的最后一项。如果不是,它可能会显着改变预期结果,因为它可能会在结果集 当时 大于所取项目的数量时删除项目。
解决此问题所需要做的就是将 Take()
的逻辑从循环中取出,以确保它最后完成。
我有两个表 Schedule 和 ScheduleItems 具有 one-to-many 关系
日程安排:
- 计划 ID(向导)
- 频道 ID(向导)
- 计划类型(字符串)
- 完成(布尔值)
计划项目:
- ScheduleItemID (Guid)
- 计划 ID (Guid)
- 标题(字符串)
- 预定时间(日期时间)
- 内容类型(字符串)
从我的 webAPI 计划项目控制器我想 return 基于 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();
}
虽然这确实 return 了一些预期的结果,但与 运行 等效的 SQL 直接查询相比,它return 的结果数量不同数据库。
显然我在这里偏离了轨道。
我考虑过放弃这个并为每个可能的查询参数变体编写一个控制器操作,但是在考虑这个时我意识到我会创建大量的控制器操作。我觉得必须有更好的方法来获得我想要的东西而不用写那么多控制器动作。
实现此目标的最佳方法是什么?
注意:我无法在控制器端使用 OData 查询,因为这破坏了客户端的自定义 JSon.NET de-serialising。
如果您期望符合逻辑 AND 逻辑,那么这个想法通常应该可行。但是,"take"
可能不是 parameters
中的最后一项。如果不是,它可能会显着改变预期结果,因为它可能会在结果集 当时 大于所取项目的数量时删除项目。
解决此问题所需要做的就是将 Take()
的逻辑从循环中取出,以确保它最后完成。