2016-08-04 17 views
1

Ich habe ein ungewöhnliches Problem mit EF 6-Code behoben, bei dem Abfragen mit dem Oracle.ManagedDataAccess.Client-Treiber manchmal mehrere Minuten dauern, bis die zugrunde liegende Abfrage ausgeführt wird 2ms. Ein Beispiel Abfrage würde wie folgt aussehen:Dynamische Generierung von Lambda-Ausdruck mit Konstanten aus Variablen

var result = users.Where(u => u.username == varUserName).FirstOrDefault(); 

Diese Abfrage kann einige Minuten dauern jedoch zurück, wenn ich die Abfrage mit der gleichen Sache mit einer Konstante in der Lambda-Funktion ersetzen, läuft es sofort:

var result = users.Where(u => u.username == "testUsername").FirstOrDefault(); 

, um dieses Problem zu umgehen, ich entweder parametrisierte SQL-Abfragen schreiben kann, oder ich kann einen geeigneten Lambda-Ausdruck Baum manuell erzeugen:

var userParam = Expression.Parameter(typeof(Entity.User), "user"); 
var userNameField = Expression.Property(userParam, "username"); 
var userNameConstant = Expression.Constant(varUserName, typeof(string)); 
var equalUserName = Expression.Equal(userNameField, userNameConstant); 
var lambda = Expression.Lambda<Func<Entity.User, bool>>(equalUserName, new ParameterExpression[] { userParam }); 
var result = users.Where(lambda).FirstOrDefault(); 

Da diese Arbeit s, es stellt sich die Frage: gibt es eine Möglichkeit, einfach Lambda-Ausdruck Bäume zu generieren, die dazu führen, Variablen direkt als Konstanten anstelle von Verweisen auf Variablen enthalten?

Zum Beispiel so etwas wie dies wäre ideal:

var lambdaExpression = (u => u.username == varUserName).ReplaceVariablesWithConstants(); 
+2

Haben Sie nicht gemeint: 'var userNameConstant = Expression.Constant (varUserName, typeof (string)); ' –

+0

Ich tat sicherlich, danke @JeroenvanLangen – fabspro

Antwort

3

es mit ExpressionVisitor relativ einfach durchgeführt werden können, welche die ConstantExpression Mitglieder wie folgt bewertet:

public static class ExpressionUtils 
{ 
    public static Expression<TDelegate> ReplaceVariablesWithConstants<TDelegate>(this Expression<TDelegate> source) 
    { 
     return source.Update(
      new ReplaceVariablesWithConstantsVisitor().Visit(source.Body), 
      source.Parameters); 
    } 

    class ReplaceVariablesWithConstantsVisitor : ExpressionVisitor 
    { 
     protected override Expression VisitMember(MemberExpression node) 
     { 
      var expression = Visit(node.Expression); 
      if (expression is ConstantExpression) 
      { 
       var variable = ((ConstantExpression)expression).Value; 
       var value = node.Member is FieldInfo ? 
        ((FieldInfo)node.Member).GetValue(variable) : 
        ((PropertyInfo)node.Member).GetValue(variable); 
       return Expression.Constant(value, node.Type); 
      } 
      return node.Update(expression); 
     } 
    } 
} 
+0

Vielen Dank. Ich bin mir sicher, dass ich meine Problemumgehung von hier aus entwickeln kann. – fabspro

1

Es irgendwie schwer ist. Sie müssen den ExpressionsTree mit einem ExpressionsVisitor ändern. Es wäre wahrscheinlich werden so etwas wie:

var lambdaExpression = ReplaceVariablesWithConstants(u => u.username == varUserName); 
+0

Vielen Dank. Ihr MSDN-Link kombiniert mit der anderen Antwort löst mein Problem! – fabspro