2010-07-22 4 views
0

J'écris une classe, elle a des requêtes. attention, la whereitem est une petite classe, ses membres du corps comprennent une expression Expression<Fun<T,bool>> lambda est utilisé pour filtrer la requêteProblèmes avec les requêtes Entity Framework

public override List<T> Find<T>(int start, int len = 10, IWhereItem<T> whereitem = null, IOrderItem<T> orders = null, bool isDetach = true) 
{ 
    var context = getInstence(); 
    var edminfo = EdmMgr[typeof (T)];//EdmMgr Include some dataservice infomation 
    ObjectQuery<T> query = context.CreateQuery<T>("[" + edminfo.TableName + "]"); 
    if (whereitem != null && whereitem.Body != null) 
    query = query.Where(whereitem.Body).AsObjectQuery(); 
    string orderString = orders == null ? "it." + edminfo.KeyName + " asc" : orders.OrderString; 
    List<T> result = start == -1 
      ? query.OrderBy(orderString).ToList() 
      : query.OrderBy(orderString).Skip(start).Take(len).ToList(); 
    //......and else 
    return result; 
} 

puis, quand je le lance, je reçois une erreur, il a dit « requête LINQ to Entities ne prend pas en charge la méthode de création de requête.Pour plus d'informations, reportez-vous à la documentation Entity Framework. "

alors je change mon code.

public override List<T> Find<T>(int start, int len = 10, IWhereItem<T> whereitem = null, IOrderItem<T> orders = null, bool isDetach = true) 
{ 
    var context = getInstence(); 
    var edminfo = EdmMgr[typeof (T)]; 
    ObjectQuery<T> query = context.CreateQuery<T>("[" + edminfo.TableName + "]"); 
    query = MemerVisitor.IncludeMembers.Aggregate(query, (current, str) => current.Include(str)); 
    string orderString = orders == null ? "it." + edminfo.KeyName + " asc" : orders.OrderString; 
    List<T> result = query.OrderBy(orderString).Skip(start).Where(whereitem.Body).Take(len).ToList(); 
    return result; 
} 

ainsi. c'est bon, mais c'est moche, non? le WHERE est après ORDERBY. quand je change leur emplacement, j'obtiens une erreur. Le type ne correspond pas. Quel autre bon moyen?

================== supplémentaires =========================== Afin de faciliter la réception appel cette méthode en passant une chaîne (par exemple "it.UserId desc") sur l'ordre de tri OrderItem, en fait WhereItem est Expression> le paquet, ma question n'est pas de savoir si implémenter le filtre est l'instruction entityframework, mais peut diviser l'opération de chaîne, parce que si la première implémentation de la Où dans la requête après il converti en IQueryObject pas ObjectQuery type, donc une fois cast, après l'implémentation de Orderby une erreur. Tels que:

 using (DataService<User> db = new DataService<User>()) 
      { 
       user = db.Find(x => x.Moreinfo.CopSchool.CopSchoolId == 13&& x.Role.Title.Equals("xxxx")).FirstOrDefault(); 
      } 

DataService que j'enveloppé la classe. L'équivalent d'un DAO. Mais est réalisé EF. Certaines requêtes peuvent être transmises, mais d'autres ne le sont pas. Les raisons ne sont pas claires. Mais certainement à cause de la conversion de type causée. J'utilise. Net 3.5sp1 vs2010 modèle de données d'entité par défaut (.Edmx)

Si je dirige l'implémentation de query.OrderBy (xxx). Ignorer (xx). Où (xxx). Prenez (xx). ToList() pour retourner les résultats, mais il y a quelques problèmes, il est le filtre de premier ordre obtenu dans le saut de xx derniers mois.

Je voudrais demander. Où (XX). OrderBy (xxx). Ignorer (xx). Prenez (xx). ToList() ... mais ne peut pas être effectué parce que le Where (Expression) à renvoyer mais pas ObjecteQuery IEnumerable (type de paramètre Expression de l'heure) ou IQueryable (paramètre de type Func time). Où ne peut être placé sur le dos, tout en saut appeler après avoir OrderBy, où si maladroit au milieu de ...

+0

@user: s'il vous plaît fournir un peu de détails sur ce problème se produit en réalité. Y a-t-il une exception? Alors s'il vous plaît le poster. Nous ne pouvons pas tous lire dans les pensées. –

Répondre

1

est ici ce que je crois qui se passe:

vous ne pouvez pas appliquer la. Où (whereitem.Body) à la requête car il contient une expression de fonction personnalisée que Entity Framework ne sait pas traduire en SQL pour s'exécuter sur la base de données.

lorsque vous placez le .Where (whereitem.Body) après le .OrderBy (orderString) .Skip (démarrer) il fonctionne correctement car l'appel .OrderBy (orderString) .Skip (start) a provoqué l'exécution du SQL et a renvoyé un IEnumerable dans la mémoire que vous pouvez maintenant exécuter votre .Where (whereitem.Body) sur cela dans la collection de mémoire. il n'a plus besoin de traduire cette expression en sql, mais l'exécute en tant que CLR. vous pouvez utiliser une expression lambda simple dans le champ Où est traduisible en SQL, ou vous pouvez forcer le sql à l'évaluer plus tôt en faisant query.AsEnumerable(). Où (...) ofcourse cela chargera beaucoup plus de résultats de la db en mémoire avant d'effectuer le filtrage.

également, le filtrage après saut et prise vous donnera des résultats différents de la filtration d'abord.

À la réflexion, ce que vous avez vraiment besoin est ceci:

Find<T>(..., Func<TEntity,bool> predicate, ...) 
{ 
... 
query.Where(predicate)... 


} 

vous devez passer l'expression lambda comme un prédicat simple, je crois que cela devrait que ce soit traduisible à SQL. (bien sûr, étant donné que le prédicat est constitué d'expressions simples qui sont elles-mêmes traduisibles par EF en sql.)

+0

J'ai mis à jour la question – Dreampuf

0

J'ai trouvé le chemin.

http://www.codeproject.com/KB/linq/IEnumerableSortByName.aspx?msg=3005452#xx3005452xx

nous pouvons utiliser la méthode extend SortEngine

private static IOrderedEnumerable<T> SortEngine<T>(this IEnumerable<T> source, string columnName, bool isAscending, bool started) 
{ 
    var item = Expression.Parameter(typeof(T), "item"); 
    var propertyValue = Expression.PropertyOrField(item, columnName); 
    var propertyLambda = Expression.Lambda(propertyValue, item); 
    // item => item.{columnName} 

    var sourceExpression = Expression.Parameter(typeof(IEnumerable<T>), "source"); 

    string methodName; 
    Expression inputExpression; 
    if (started) 
    { 
     methodName = isAscending ? "ThenBy" : "ThenByDescending"; 
     inputExpression = Expression.Convert(sourceExpression, typeof(IOrderedEnumerable<T>)); 
     // ThenBy requires input to be IOrderedEnumerable<T> 
    } 
    else 
    { 
     methodName = isAscending ? "OrderBy" : "OrderByDescending"; 
     inputExpression = sourceExpression; 
    } 

    var sortTypeParameters = new Type[] { typeof(T), propertyValue.Type }; 
    var sortExpression = Expression.Call(typeof(Enumerable), methodName, sortTypeParameters, inputExpression, propertyLambda); 
    var sortLambda = Expression.Lambda<Func<IEnumerable<T>, IOrderedEnumerable<T>>>(sortExpression, sourceExpression); 
    // source => Enumerable.OrderBy<T, TKey>(source, item => item.{columnName}) 

    return sortLambda.Compile()(source); 
} 

public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> source, string columnName) 
{ 
    return SortEngine(source, columnName, true, false); 
} 

public static IOrderedEnumerable<T> OrderByDescending<T>(this IEnumerable<T> source, string columnName) 
{ 
    return SortEngine(source, columnName, false, false); 
} 

public static IOrderedEnumerable<T> ThenBy<T>(this IOrderedEnumerable<T> source, string columnName) 
{ 
    return SortEngine(source, columnName, true, true); 
} 

public static IOrderedEnumerable<T> ThenByDescending<T>(this IOrderedEnumerable<T> source, string columnName) 
{ 
    return SortEngine(source, columnName, false, true); 
} 
Questions connexes