如何通过URL向ASP.NET Web API传递对象列表查询数据库表?
解决FromQuery绑定Condition数组为空的问题
问题根源
ASP.NET Core默认不支持直接将URL查询参数里的JSON字符串绑定到复杂对象数组,你当前用的Swagger生成的是JSON格式的conditions参数,框架没法自动解析,所以conditions一直为空。
快速解决:修改参数传递格式
把查询参数改成索引式键值对的格式,框架就能自动绑定了:
http://localhost:5001/api/datatable?conditions[0].variable=vara&conditions[0].op=>&conditions[0].value=20&conditions[1].variable=varb&conditions[1].op=>&conditions[1].value=10
如果用Swagger调试,直接在参数输入框按对象数组结构填写,Swagger会自动转换成正确格式。
进阶方案:支持JSON格式的查询参数
如果必须用JSON字符串传递,需要自定义模型绑定器:
- 创建自定义绑定器类:
public class JsonQueryModelBinder : IModelBinder { public Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext == null) throw new ArgumentNullException(nameof(bindingContext)); var values = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); if (values.Length == 0) return Task.CompletedTask; try { var model = JsonSerializer.Deserialize(values.FirstValue, bindingContext.ModelType, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); bindingContext.Result = ModelBindingResult.Success(model); } catch { bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, "Invalid JSON format"); } return Task.CompletedTask; } }
- 创建绑定器提供器:
public class JsonQueryModelBinderProvider : IModelBinderProvider { public IModelBinder GetBinder(ModelBinderProviderContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); if (context.Metadata.ModelType.IsArray && context.Metadata.ModelType.GetElementType().IsClass) { return new BinderTypeModelBinder(typeof(JsonQueryModelBinder)); } return null; } }
- 在Program.cs里注册绑定器:
builder.Services.AddControllers(options => { options.ModelBinderProviders.Insert(0, new JsonQueryModelBinderProvider()); });
完成后Action就能正常接收JSON格式的conditions参数了。
额外优化:修复过滤逻辑的性能问题
你当前用反射写的过滤逻辑,EF Core无法转换成SQL语句,会先加载全表数据到内存再过滤,数据量大时性能极差。建议用表达式树构建查询:
foreach (var condition in conditions) { var parameter = Expression.Parameter(typeof(ScreenerData), "data"); var property = Expression.Property(parameter, condition.variable); var constant = Expression.Constant(condition.value, typeof(double)); // 处理属性类型转换(若属性不是double类型) var convertedProperty = Expression.Convert(property, typeof(double)); Expression comparison; switch (condition.op) { case "==": comparison = Expression.Equal(convertedProperty, constant); break; case "!=": comparison = Expression.NotEqual(convertedProperty, constant); break; case ">": comparison = Expression.GreaterThan(convertedProperty, constant); break; case "<": comparison = Expression.LessThan(convertedProperty, constant); break; default: return BadRequest("Unsupported operator"); } var lambda = Expression.Lambda<Func<ScreenerData, bool>>(comparison, parameter); query = query.Where(lambda); }
这样EF Core能将表达式转换成对应SQL,在数据库层面完成过滤,性能会大幅提升。
内容的提问来源于stack exchange,提问作者JPWilson
相关产品推荐
相关产品推荐

