I am working on LINQ to SQL translator. It should translate LINQ queries to SQL. I am focused on creating WHERE part of the query. I am traversing LINQ Expression tree and then I get to a problem that I can't get to the value of actual parameter passed to the method that contains LINQ call.
NOTE: I am not using LINQ to SQL, nor Entity Framework, nor NHibernate because I simply can't since VB6 Legacy system is in the game.
So what I am trying to achieve is to call somewhere on high level this:
int? parameterForCall = cmb.SelectedValue;
Then I have a method like this and it is in ExpenseDAL
class that calls BaseDAL<Expense>.GetAll(X)
:
public IList<Expense> GetAll(int? parameterForCall)
{
IList<Expense> expenses = BaseDAL<Expense>.GetAll(t => t.Fixed ==
parameterForCall);
}
GetAll
method has signature like this:
public static IList<T> GetAll(Expression<Func<T, bool>> predicate = null);
Then I am calling GetCondition
method that converts expression to SQL:
private static string GetCondition(Expression predicate = null);
It is a recursive function. In it I get to a situation that I need to get to parameter that I passed to GetAll
expression, named parameterForCall
.
The problem is that I can write this:
dynamic value = (predicate as ConstantExpression);
And in ImmediateWindow I can see that value.Value is written like this:
{FMC.Proxy.Common.BaseDAL.}
parameterForCall: 19
But I can'开发者_开发问答t get to the value 19. And I want it so I can convert it to value to put to SQL string.
Does anyone know how to get to value 19 so I can use it in the code?
My answer assumes - and your question supports this assumption - that the predicate passed into GetCondition
is of type ConstantExpression
.
It isn't trivial to get that value, because parameterForCall
is captured in an automatically generated class. You can see that, when you look at the output of (predicate as ConstantExpression).Value.GetType()
. In my case, this outputs:
UserQuery+<>c__DisplayClass0
This class in turn has a public field named parameterForCall
. Now, you have two possibilities to get that value:
You know the name of that field, because you control the method in which this Expression is created. In that case, you can use this code to get the value:
var constantExpression = (ConstantExpression)predicate; dynamic autoGeneratedClass = constantExpression.Value; object value = autoGeneratedClass.parameterForCall;
value.GetType()
will returnSystem.Int32
and thevalue
will be a boxed int with the value 19.You don't know the name of that field. In that case, it is harder. You could use reflection to get the value of the only public visible field, but if you do this, you would make a lot of assumptions about the automatically generated class.
You simply have to get the property from the dynamic
you already got:
dynamic value = (predicate as ConstantExpression);
int? parameterForCall = value.parameterForCall;
If you don't know the name of the parameter (and perhaps the type) you can use reflection. The parameter you are looking for exists as a public field of the object returned by ConstantExpression.Value
. This is not something specified anywhere so use it at your own risk.
This small piece of code demonstrates that:
class Expense { public int Fixed { get; set; } }
void Test(int? parameterForCall) {
Expression<Func<Expense, bool>> predicate = t => t.Fixed == parameterForCall;
var parameter = (
(ConstantExpression) (
(MemberExpression) (
(BinaryExpression) predicate.Body
).Right
).Expression
).Value;
var fieldInfo = parameter.GetType().GetFields().First();
var name = fieldInfo.Name;
var value = fieldInfo.GetValue(parameter);
Console.WriteLine(name + " = " + value);
}
If you execute Test(19)
the output is parameterForCall = 19
.
Hope this Stackoverflow answer helps
expression trees linq get value of a parameter?
Basically you might have to compile the expression before being able to programmatically get the property value.
Watch for performance penalty though. Good luck.
精彩评论