Reputation: 1379
I am developing a simple class that maps any Tuples from database, by convention, to CLR objects.
Here in my work, i cannot use EntityFramework, because database is giant and we have splitted models and is impossible to cross different contexts.
So i started develop my own ORM mapper, that generate insert, update and delete commands. i am trying to develop the select method, that generates select CMD.
This method receives a Expression<T, bool>
filter by parameter that i want to filter the data.
One thing that i really want to use is something like:
int value = 1;
int valu2 = 40;
mapper.Select<MyEntity>(m => m.id> value && m.id<= value2);
The big problem is that filter.body.toString()
generates a string as is, and, what i really want to do is to replace the values of "value" and "value2" by their values declared on their variables...
Someone can give me a light?
Really Thanks to all!
Upvotes: 0
Views: 576
Reputation: 1379
I parsed the expr tree in a simple manner, just to build the filter.
Here's how i did it.
private static String ParseFilter(Expression expr)
{
return ParseFilter(expr, new ExpressionUtilFilterClass()).data.ToString();
}
// Recursive algorithm
private
static
ExpressionUtilFilterClass // Return type
ParseFilter(
Expression expr,
ExpressionUtilFilterClass info // Used to pass information in recursive manner
)
{
Type exprType = expr.GetType();
if ( exprType != typeof(BinaryExpression) && exprType != typeof(MemberExpression) && exprType != typeof(ConstantExpression) )
throw new InvalidOperationException("unsupported filter");
if ( exprType == typeof(BinaryExpression) )
{
//
// We have 2 expressions (left and right)
//
BinaryExpression bExpr = (BinaryExpression)expr;
ExpressionUtilFilterClass recursion;
StringBuilder subOperation = new StringBuilder();
recursion = ParseFilter(bExpr.Left, info); // Go left in depth - we don't know the type yet
subOperation.Append("( ");
subOperation.Append(recursion.data);
subOperation.Append(" ");
subOperation.Append(_expressionOperator[bExpr.NodeType]);
subOperation.Append(" ");
recursion = ParseFilter(bExpr.Right, recursion); // Pass reference that contains type information!
subOperation.Append(recursion.data);
subOperation.Append(" )");
// Affect data subpart and pass to upper caller
recursion.data = subOperation.ToString();
return recursion;
}
else
{
MemberExpression mExpr;
ParameterExpression pExpr;
ConstantExpression cExpr;
//
// We need distinct if we are accessing to capturated variables (need map to sql) or constant variables
//
if ( ( mExpr = expr as MemberExpression ) != null )
{
if ( ( pExpr = ( mExpr.Expression as ParameterExpression ) ) != null )
{
info.parameterType = mExpr.Expression.Type; // Type of parameter (must be untouched)
info.data = GetMappingForProperty(info.parameterType, mExpr.Member.Name); // Must have a map to SQL (criar metodo que faz mapeamento)!!!!!!!!!!!!!!!!!
return info;
}
else
{
cExpr = (ConstantExpression)mExpr.Expression;
object obj = cExpr.Value; // Get anonymous object
string objField = mExpr.Member.Name;
FieldInfo value = obj.GetType().GetField(objField); // Read native value
string nativeData = value.GetValue(obj).ToString();
info.data = nativeData;
return info;
}
}
else
{
cExpr = (ConstantExpression)expr;
string nativeData = cExpr.Value.ToString();
info.data = nativeData;
return info;
}
}
}
Upvotes: 0
Reputation: 112279
There is no simple way to achieve this. You will have to parse the entire syntax tree in a recursive manner and convert it to a where clause, which looks like this:
WHERE id > 1 AND id < 40
See a blog on Expression Tree Basics. It is not the full answer to your question; however, it may give you a starting point.
Upvotes: 1