在运行时创建动态LINQ查询表达式,转换为参数化SQL查询
我想为IQueryable创建自定义表达式。 示例扩展方法:
public static IQueryable GetByIntTest(this IQueryable qSource, Expression<Func> field, int? value) { if (value == null) return qSource; ConstantExpression constantExpression = Expression.Constant(value, typeof(int?)); BinaryExpression binaryExpression = Expression.Equal(field.Body, constantExpression); var predicate = Expression.Lambda<Func>(binaryExpression, field.Parameters); return qSource.Where(predicate); }
它的工作原理,但问题是它转换为非参数化的sql。
例如没有扩展名的代码
int userId = 3; var testUsual = Context.Set().Where(u => u.Id == userId);
转换为下一个sql
SELECT [Extent1].[Id] AS [Id], [Extent1].[FirstName] AS [FirstName], [Extent1].[LastName] AS [LastName], FROM [dbo].[User] AS [Extent1] WHERE [Extent1].[Id] = @p__linq__0
和扩展方法
int userId = 3; var testExtension = Context.Set().GetByIntTest(u => u.Id, userId);
翻译成
SELECT [Extent1].[Id] AS [Id], [Extent1].[FirstName] AS [FirstName], [Extent1].[LastName] AS [LastName], FROM [dbo].[User] AS [Extent1] WHERE 3 = [Extent1].[Id]
那么如何编写表达式来生成像 sql中的@p_ linq _0这样的东西呢?
更新
感谢我们的回答,我重写了我的扩展方法,现在它生成@p_ linq _0,因为我想要。
public static IQueryable GetByIntTest(this IQueryable qSource, Expression<Func> field, int? value) { if (value == null) return qSource; var binaryExpression = Expression.Equal(field.Body, ExpressionClosureFactory.GetField(value)); var predicate = Expression.Lambda<Func>(binaryExpression, field.Parameters); return qSource.Where(predicate); } public class ExpressionClosureFactory { public static MemberExpression GetField(TValue value) { var closure = new ExpressionClosureField { ValueProperty = value }; return Expression.Field(Expression.Constant(closure), "ValueProperty"); } class ExpressionClosureField { public T ValueProperty; } }
我有这个问题。 您正在生成u => u.Id == 3
作为表达式,而C#编译器将生成:
class CompilerGeneratedClosure { public int UserId; } var closure = new CompilerGeneratedClosure() { UserId = 3 }; u => u.Id == closure.UserId
像C#编译器那样做。 创建一个类来保存ID或使用元组。 将closure
注入为常量表达式。