2009-01-19 7 views
2

Y at-il quelqu'un avec de l'expérience dans l'écriture de fournisseurs Linq personnalisés? Ce que j'essaie de faire est de dire si une MemberExpression qui est une propriété sur un objet métier doit être incluse dans le SQL, ou traitée comme une constante, car elle provient d'une variable locale qui se trouve être une entreprise objet.Détermination de la portée d'une cible MemberExpressions

Ainsi, par exemple, si vous avez ceci:

Customer c = LoadCustomerFromDatabase(); 

var orders = from o in db.Orders() where o.CustomerID == c.CustomerID select o; 

Pour le moment, mon traducteur de requête essaiera d'exécuter SELECT * FROM orders o where o.CustomerID = c.CustomerID, ce qui bien sûr ne fonctionne pas. Ce que je voudrais faire est d'examiner la MemberExpression sur le c.CustomerID et essayer de travailler si c'est une variable locale, ou juste quelque chose qui est utilisé dans le cadre de l'expression Linq.

J'ai réussi à le faire comme un second passage sur la requête, à la recherche de champs que SQL Server ne sera pas capable de lier, et d'injecter leurs valeurs à la place, mais si possible je voudrais que tout se passe en même temps. J'ai essayé de regarder l'expression Type propriété, et IsAutoClass, mais c'était juste une supposition parce qu'il contenait le mot Auto. Et ça n'a pas marché :)

Répondre

1

Eh bien, je ne sais pas si vous pouvez le réduire à un passage, mais vous pouvez obtenir des informations sur le membre, et si cela coïncide avec une autre variable que vous avez déclarée être partie de la requête (dans ce cas "o"), vous l'utilisez pour générer votre requête.

Sinon, vous supposer qu'il est une constante, puis branchez cette valeur dans.

Malheureusement, parce que vous pouvez avoir des états (en plus de l'instruction let) à plusieurs endroits dans la requête, il doesn Il ne semble pas que vous puissiez le faire en un seul passage, car vous devez connaître toutes les variables de la requête à l'avance.

1

D'accord, après une analyse statistique rapide (c.-à-comparer les propriétés individuelles manuellement), DeclaringType, ReflectedType et Namespace sont lorsque le paramètre Lambda n'est pas portée » incendies. Alors

à moins que quelqu'un arrive avec une meilleure réponse, qui pourrait être tout ce que je dois aller sur

1

Dans un cas où l'expression, vous êtes à la recherche d'un Expression<Func<T,bool>> -.. ce qui signifie que le lambda externe doit avoir un seul ParameterExpression avec le type T

Si une comparaison concerne la rangée, il aura (comme un ancêtre) ce ParameterExpression; si c'est une variable locale, elle aura (comme ancêtre) un ConstantExpression - cependant, le type de cette expression constante sera généré par le compilateur pour faire face à toutes les variables capturées utilisées dans l'expression.

comme ceci:

using System; 
using System.Linq.Expressions; 
class Foo 
{ 
    public string Name { get; set; } 
    static void Main() 
    { 
     var exp = (LambdaExpression) GetExpression(); 
     WalkTree(0, exp.Body, exp.Parameters[0]); 

    } 
    static void WriteLine(int offset, string message) 
    { 
     Console.WriteLine(new string('>',offset) + message); 
    } 
    static void WalkTree(int offset, Expression current, 
     ParameterExpression param) 
    { 
     WriteLine(offset, "Node: " + current.NodeType.ToString()); 
     switch (current.NodeType) 
     { 
      case ExpressionType.Constant: 
       WriteLine(offset, "Constant (non-db)" 
        + current.Type.FullName); 
       break; 
      case ExpressionType.Parameter: 
       if (!ReferenceEquals(param, current)) 
       { 
        throw new InvalidOperationException(
         "Unexpected parameter: " + param.Name); 
       } 
       WriteLine(offset, "db row: " + param.Name); 
       break; 
      case ExpressionType.Equal: 
       BinaryExpression be = (BinaryExpression)current; 
       WriteLine(offset, "Left:"); 
       WalkTree(offset + 1, be.Left, param); 
       WriteLine(offset, "Right:"); 
       WalkTree(offset + 1, be.Right, param); 
       break; 
      case ExpressionType.MemberAccess: 
       MemberExpression me = (MemberExpression)current; 
       WriteLine(offset, "Member: " + me.Member.Name); 
       WalkTree(offset + 1, me.Expression, param); 
       break; 
      default: 
       throw new NotSupportedException(
        current.NodeType.ToString()); 
     } 
    } 

    static Expression<Func<Foo, bool>> GetExpression() 
    { 
     Foo foo = new Foo { Name = "abc" }; 

     return row => row.Name == foo.Name; 
    }  
} 
Questions connexes