2016-04-17 13 views
2

In meinem speziellen Szenario erstelle ich dynamisch eine SQL-Anweisung, um nach Datensätzen zu suchen. Dies geschieht serverseitig in WebApi auf der Business-Service-Schicht. Jetzt möchte ich diese Funktionalität erweitern, so dass die WHERE-Klausel auch auf der Clientseite gesetzt werden kann. Ich möchte strong-typed verwenden, damit ich keine Spaltennamen auf dem Client fest codiere.Wie bekomme ich Lambda-Ausdrucksparameter?

Bisher habe ich folgende:

1) die Spalten der Ansicht Rau aus den INFORMATION_SCHEMA und füllt ein Dictionary<string, object> so dass die Spaltenwerte zu einem späteren Zeitpunkt festgelegt werden. Ich könnte zu einer benutzerdefinierten Klasse wechseln, so dass ich ein Vergleichsfeld anstelle von column_name = column_value hinzufügen kann.

2) Ich habe ein benutzerdefiniertes Attribut und eine Klasse, die nur die Such Spalten enthält, die ich an den Client verfügbar machen möchten:

public class CustomerSearchDto 
{ 
    [SearchColumn(Name = "customer_type")] 
    public CustomerType CustomerType { get; set; } 

    [SearchColumn(Name = "city")] 
    public string City { get; set; } 

    public CustomerSearchDto() 
    { } 
} 

3) So im Client, jetzt kann ich tun:

Wie kann ich diesen Lambda-Ausdruck nehmen und die Spaltenliste aus (1) und die Spaltennamen aus (2) kennen, den Wert der entsprechenden Spalte im Wörterbuch festlegen?

Antwort

0

Es gibt zu viele Annahmen, aber man kann mit so etwas wie folgen beginnen:

static void SetValue<T>(Dictionary<string, object> target, Expression<Func<T, bool>> predicate) 
{ 
    var comparison = predicate.Body as BinaryExpression; 
    Debug.Assert(comparison != null); 
    var member = (comparison.Left.NodeType == ExpressionType.Convert ? 
     ((UnaryExpression)comparison.Left).Operand : 
     comparison.Left) as MemberExpression; 
    Debug.Assert(member != null); 
    var value = comparison.Right as ConstantExpression; 
    Debug.Assert(value != null); 
    var attribute = Attribute.GetCustomAttribute(member.Member, typeof(SearchColumnAttribute)) as SearchColumnAttribute; 
    var columnName = attribute?.Name ?? member.Member.Name; 
    var columnValue = value.Value; 
    target[columnName] = columnValue; 
} 

Test:

Expression<Func<CustomerSearchDto, bool>> predicate = (x => x.CustomerType == CustomerType.Private); 
var dict = new Dictionary<string, object>(); 
SetValue(dict, predicate); 
0

Statt ein Wörterbuch zu bauen und dann eine Abfrage aus, dass, könnten Sie gehen von Ihrem clientseitigen Ausdruck zu Ihrem SQL-Ausdruck in einem Schritt, indem Sie ihn unter Verwendung eines ExpressionVisitor umschreiben.

Ihre ExpressionVisitor würde die entsprechende Methode, z. protected override Expression VisitMember(MemberExpression node) und innerhalb dieser Methode würde es den clientseitigen Feldnamen in den serverseitigen Feldnamen konvertieren.

Sie haben immer noch das Problem der Serialisierung Ihrer Ausdrücke Client-Seite und Deserialisierung sie serverseitig, aber sobald Sie sie haben, können Sie den Besucher verwenden, um sie für SQL neu zu schreiben.