问题
I want to create my custom expression for IQueryable. Sample extension method:
public static IQueryable<T> GetByIntTest<T>(this IQueryable<T> qSource, Expression<Func<T, int?>> 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<T, bool>>(binaryExpression, field.Parameters);
return qSource.Where(predicate);
}
It works, but problem is that it translate into not parameterized sql.
For example code without extension
int userId = 3;
var testUsual = Context.Set<User>().Where(u => u.Id == userId);
Translate into next 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
And extension method
int userId = 3;
var testExtension = Context.Set<User>().GetByIntTest(u => u.Id, userId);
Translate into
SELECT [Extent1].[Id] AS [Id],
[Extent1].[FirstName] AS [FirstName],
[Extent1].[LastName] AS [LastName],
FROM [dbo].[User] AS [Extent1]
WHERE 3 = [Extent1].[Id]
So how can I write expression for generating something like @p_linq_0 in sql?
Update
Thanks to usr answer, I rewrite my extension method and now it generate @p_linq_0 as i want.
public static IQueryable<T> GetByIntTest<T>(this IQueryable<T> qSource, Expression<Func<T, int?>> field, int? value)
{
if (value == null)
return qSource;
var binaryExpression = Expression.Equal(field.Body, ExpressionClosureFactory.GetField(value));
var predicate = Expression.Lambda<Func<T, bool>>(binaryExpression, field.Parameters);
return qSource.Where(predicate);
}
public class ExpressionClosureFactory
{
public static MemberExpression GetField<TValue>(TValue value)
{
var closure = new ExpressionClosureField<TValue>
{
ValueProperty = value
};
return Expression.Field(Expression.Constant(closure), "ValueProperty");
}
class ExpressionClosureField<T>
{
public T ValueProperty;
}
}
回答1:
I have had this problem. You are generating u => u.Id == 3
as an expression while the C# compiler would generate:
class CompilerGeneratedClosure { public int UserId; }
var closure = new CompilerGeneratedClosure() { UserId = 3 };
u => u.Id == closure.UserId
Do it like the C# compiler would. Create a class to hold the ID or use a tuple. Inject closure
as a constant expression.
来源:https://stackoverflow.com/questions/21073663/create-dynamic-linq-query-expression-at-runtime-which-translates-into-a-paramete