如何让EF Core 6生成带参数化查询的IQueryable<T>
解决EF Core中ApplyFilter扩展方法不生成参数化SQL的问题
问题背景
实现了用于动态构建过滤条件的ApplyFilter扩展方法,但调用时生成的SQL直接将过滤值硬编码(如WHERE [m].[BrandId] = 2618),而非参数化形式,存在SQL注入风险。
问题根源
代码中使用Expression.Constant将过滤值直接嵌入表达式树,EF Core会把这类直接的常量值编译为SQL中的硬编码内容,不会自动参数化。只有当表达式树引用外部局部变量时,EF Core才会将其识别为需要参数化的输入。
修改方案
修改BuildCriteriaExpression方法中创建常量表达式的逻辑,将转换后的值先赋值给局部变量,再通过Expression.Constant引用该变量,让EF Core自动生成参数化SQL。
关键修改点
单值过滤场景(Equal/NotEqual等操作符)
原代码:var constantValue = Convert.ChangeType(criteriaNode.Value, propertyType); constant = Expression.Constant(constantValue);修改为:
var constantValue = Convert.ChangeType(criteriaNode.Value, propertyType); // 用局部变量存储值,触发EF Core参数化 var valueHolder = constantValue; constant = Expression.Constant(valueHolder, propertyType);Between操作符场景
原代码:var min = Expression.Constant(constantValues[0], propertyType); var max = Expression.Constant(constantValues[1], propertyType);修改为:
var minValue = constantValues[0]; var maxValue = constantValues[1]; var min = Expression.Constant(minValue, propertyType); var max = Expression.Constant(maxValue, propertyType);Any操作符场景
原代码:var arrayInitializer = convertedValue.Select(x => Expression.Constant(x, propertyUnderlyingType));修改为:
var arrayInitializer = convertedValue.Select(x => { var item = x; return Expression.Constant(item, propertyUnderlyingType); });
修改后效果
修改后生成的SQL会变为参数化形式,例如:
SELECT [a].[AssetId], [a].[AssetCode], [a].[SerialNumber], [a].[LocationId], [m].[ModelName], [m].[Description] AS [ModelDescription], [b].[BrandName], [a0].[AssetTypeName], [c].[CategoryName] FROM [Asset] AS [a] INNER JOIN [Model] AS [m] ON [a].[ModelId] = [m].[ModelId] INNER JOIN [Brand] AS [b] ON [m].[BrandId] = [b].[BrandId] INNER JOIN [AssetType] AS [a0] ON [m].[AssetTypeId] = [a0].[AssetTypeId] INNER JOIN [Category] AS [c] ON [m].[CategoryId] = [c].[CategoryId] WHERE [m].[BrandId] = @__valueHolder_0
内容的提问来源于stack exchange,提问作者Abdelrahman
相关产品推荐
相关产品推荐

