我有两个表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()
的逻辑从循环中取出,以确保它最后完成。