Al punto (3) nel mio codice ho definito una query chiamata query1 in cui ho definito un'espressione lambda .Where. Questa query è in qualche modo dinamica ma contiene ancora elementi statici, si riferisce sempre al Type Employee e alla sua proprietà (int) ClientID.
Ora mi piace molto rendere il riferimento al tipo e alla sua proprietà dinamica, in base ai parametri del metodo che, per esempio, sono mostrati sotto il punto (1).
Quello che ho cercato di fare finora è rendere completamente dinamica la parte statica della query definita al punto (3) sostituendola con un albero di espressioni più elaborato come scritto in (4), (5) e (6). Ma quando provo ad aggiungere tutto insieme, dico che chiamo. Dove ci sono parametri sbagliati. Non so come chiamare. Dove sono i parametri giusti per creare una selezione completamente dinamica.
Qualcuno sa per risolvere questo problema? Ho passato una giornata alla ricerca e non ho ancora trovato una soluzione.
dsMain domainService = new dsMain();
//(1)i want to rewrite the following four variables to method-parameters
Type entityType = typeof(Employee);
String targetProperty = "ClientID";
Type entityProperty = typeof(Employee).GetProperty(targetProperty).PropertyType;
int idToDelete = 5;
//(2)create expression-function: idToDelete == entityType.targetProperty (in this case: Employee.ClientID)
ParameterExpression numParam = Expression.Parameter(entityProperty, targetProperty.Substring(0, 3));
ConstantExpression equalTarget = Expression.Constant(idToDelete, idToDelete.GetType());
BinaryExpression intEqualsID = Expression.Equal(numParam, equalTarget);
Expression<Func<int, bool>> lambda1 =
Expression.Lambda<Func<int, bool>>(
intEqualsID,
new ParameterExpression[] { numParam });
//(3)I want to create query1 fully dynamic, so defining Employee or an other type and its property at run time
WhereClause = lambda1.Compile();
IQueryable<Employee> employees = domainService.GetEmployees();
var query1 = employees.Where<Employee>(C => WhereClause.Invoke(C.ClientID)).Expression;
//(4)create the operand body {value(ASP.test_aspx).WhereClause.Invoke(E.ClientID)}
var operandbodyMethod = WhereClause.GetType().GetMethod("Invoke");
var operandbodyType = typeof(System.Boolean);
var operandbodyArgs1Expression = Expression.Parameter(entityType, entityType.Name.Substring(0, 1));
var operandbodyArgs1 = Expression.MakeMemberAccess(operandbodyArgs1Expression, entityType.GetMember(targetProperty)[0]);
var operandBodyObjectExp = Expression.Constant(this, this.GetType());
var operandbodyObject = Expression.MakeMemberAccess(operandBodyObjectExp, this.GetType().GetMember("WhereClause")[0]);
//(5)create the operand {E => value(ASP.test_aspx).WhereClause.Invoke(E.ClientID)}
var operandbody = Expression.Call(operandbodyObject, operandbodyMethod, operandbodyArgs1);
var operandParameter = Expression.Parameter(entityType, entityType.Name.Substring(0, 1));
var operandType = typeof(Func<,>).MakeGenericType(entityType, typeof(System.Boolean));
//(6)
var operand = Expression.Lambda(operandType, operandbody, new ParameterExpression[] { operandParameter });
var expressionType = typeof(Expression<>).MakeGenericType(operandType);
var completeWhereExpression = Expression.MakeUnary(ExpressionType.Quote, operand, expressionType);
//(7)the line below does not work
var query2 = employees.Where<Employee>(completeWhereExpression).Expression;
Grazie mille per aver letto la mia domanda! Se hai domande sulla mia domanda, per favore chiedi a loro :)
Questo è piuttosto difficile da considerare da solo, ma la prima cosa che si verifica è che Compile
sembra fuori luogo per IQueryable
- che funzionerà raramente (LINQ-to-Objects è l'eccezione).
Un equivalente a WhereClause.Invoke(C.ClientID)
consiste nell'utilizzare Expression.Invoke
per chiamare una sottoespressione, ma anche questo è flakey: LINQ-to-SQL lo supporterà, EF (almeno nella 3.5) no ( forse "no", non ho ricontrollato in 4.0). In definitiva, sarebbe più robusto creare lambda1
come Expression<Func<Employee,bool>>
se possibile:
ParameterExpression empParam = Expression.Parameter(typeof(Employee),"emp");
ConstantExpression equalTarget = Expression.Constant(idToDelete, idToDelete.GetType());
BinaryExpression intEqualsID = Expression.Equal(
Expression.PropertyOrField(empParam, targetProperty), equalTarget);
Expression<Func<Exmployee, bool>> lambda1 =
Expression.Lambda<Func<int, bool>>(
intEqualsID,
empParam);
Quindi passa questo a Where
:
var query1 = employees.Where(lambda1);