2013-10-23 14 views
7

Desidero creare un'espressione dinamica di linq per la clausola SQL in EF 6.0 con il codice approc. Nota che sono nuovo per le espressioni. Quello che voglio ottenere èAlbero di espressioni di query linq dinamiche per la clausola SQL IN utilizzando il framework Entity

select * from Courses where CourseId in (1, 2, 3, 4) 
//CourseId is integer 

La query di linq normale si presenta così. Ma voglio interrogare in modo dinamico

string[] ids = new string[]{"1", "2", "3", "4"}; 
var courselist = DBEntities.Courses.Where(c => ids.Contains(SqlFunctions.StringConvert((decimal?)c.CourseId))) 

Ci sono due modi per fare espressione dinamica.
1) uno modi è quello di collegare attraverso ids e rendere le espressioni
Il codice di seguito creerà la seguente espressione in vista di debug

{f => ((StringConvert(Convert(f.CourseId)).Equals("23") Or StringConvert(Convert(f.CourseId)).Equals("2")) Or StringConvert(Convert(f.CourseId)).Equals("1"))} 

espressione dinamica è

var param = Expression.Parameters(typeof(Course), "f") 
MemberExpression property = Expression.PropertyOrField(param, "CourseId");     
MethodInfo mi = null; 
MethodCallExpression mce = null; 
if (property.Type == typeof(int)) 
{ 
    var castProperty = Expression.Convert(property, typeof(double?)); 
    var t = Expression.Parameter(typeof(SqlFunctions), "SqlFunctions"); 
    mi = typeof(SqlFunctions).GetMethod("StringConvert", new Type[] { typeof(double?) }); 
    mce = Expression.Call(null,mi, castProperty); 
} 
mi = typeof(string).GetMethod("Equals", new Type[]{ typeof(string)});    
BinaryExpression bex = null; 
if (values.Length <= 1) 
{ 
    return Expression.Lambda<Func<T, bool>>(Expression.Call(mce, mi,  Expression.Constant(values[0]), param)); 
} 
//var exp1 = Expression.Call(mce, mi, Expression.Constant(values[0])); 
for (int i = 0; i < values.Length; i++) 
{    
    if (bex == null) 
    { 
     bex = Expression.Or(Expression.Call(mce, mi, Expression.Constant(values[i])), Expression.Call(mce, mi, Expression.Constant(values[i + 1]))); 
     i++; 
    } 
    else    
     bex = Expression.Or(bex, Expression.Call(mce, mi, Expression.Constant(values[i]))); 

}//End of for loop 
return Expression.Lambda<Func<T, bool>>(bex, param); 

2) Il secondo modo in cui che ho provato (debug view)

{f => val.Contains("23")} //val is parameter of values above
L'espressione dinamica ESSIONE per sopra che ho provato è

var param = Expression.Parameters(typeof(Course), "f") 
MemberExpression property = Expression.PropertyOrField(param, "CourseId"); 
var micontain = typeof(Enumerable).GetMethods().Where(m => m.Name == "Contains" && m.GetParameters().Length == 2).Single().MakeGenericMethod(typeof(string)); 
var mc = Expression.Call(micontain, Expression.Parameter(values.GetType(), "val"), Expression.Constant("2"));//NOTE: I haven't use CourseId for now as i am getting conversion error 
return Expression.Lambda<Func<T, bool>>(mc, param); 

ottengo i seguenti errori

  • LINQ alle entità non riconosce il metodo 'System.String StringConvert (System.Nullable`1 [System.Double]) "metodo, e questo metodo non può essere tradotto in un'espressione di negozio quando utilizzo la prima metodologia . So che non posso usare ToString con EF questo è il motivo per cui ho usato SqlFunctions ma non funziona per me.
  • Il parametro 'val' non era legato in LINQ to Entities specificato tua ricerca espressione usando secondo la metodologia

sto cercando questo da ultimi 4 giorni. L'ho cercato su google ma non ho trovato nessuna soluzione adatta. Mi aiuti per favore.

risposta

8

Dopo un sacco di lotta ho trovato la soluzione alla mia domanda. voglio ottenere questa query SQL

select * from Courses where CourseId in (1, 2, 3, 4) 

utilizzando LINQ to Entities, ma voglio passare nella lista (1,2,3,4) in modo dinamico per query LINQ. Ho creato una classe di estensione per questo scopo.

public static class LinqExtensions 
{ 
    public static Expression<Func<T, bool>> False<T>() { return f => false; } 
    public static Expression<Func<T, bool>> In<T, TValue>(this Expression<Func<T, bool>> predicate,string propertyName, List<TValue> values) 
    {    
      var param = predicate.Parameters.Single(); 
      MemberExpression property = Expression.PropertyOrField(param, propertyName);    
      var micontain = typeof(List<TValue>).GetMethod("Contains");    
      var mc = Expression.Call(Expression.Constant(values), micontain, property); 
      return Expression.Lambda<Func<T, bool>>(mc, param); 
    } 
} 

L'utilizzo di LinqExtensions

var pred = LinqExtensions.False<Course>(); //You can chain In function like LinqExtensions.False<Course>().In<Course, int>("CourseId", inList); 
var inList= new List<int>(){1, 2, 3}; //Keep in mind the list must be of same type of the Property that will be compared with. In my case CourseId is integer so the in List have integer values 
pred =pred.In<Course, int>("CourseId", inList); //TValue is int. As CourseId is of type int. 
var data = MyEntities.Courses.Where(pred); 

spero che questo potrebbe essere utile per qualcuno

0

hai visto il tipo di

var courselist = DBEntities.Courses.Where(c => ids.Contains(c.CourseId))) 

sopra affermazione non sarebbe tornato elenco effettivo dei corsi. La query non è ancora stata eseguita. Restituisce solo IQuereable. La query viene eseguito quando si chiama in realtà il metodo ToList() su di esso

così, la soluzione è ..

  1. Crea un array di ID che utilizzano per il ciclo e poi semplicemente esegue la query di seguito

  2. var courselist = DBEntities.Courses.Where(c => ids.Contains(c.CourseId))).ToList()

+0

So bene che restituisca IQuerable elenco non reale. ma non hai ricevuto la mia domanda. Voglio fare la stessa cosa ids.Contains (c.CourseId) usando dinamicamente l'albero delle espressioni – Ali

Problemi correlati