2013-06-26 7 views
6

Ich frage mich, ob ServiceStack.OrmLite die JoinSqlBuilder erlauben die folgende einfache Abfrage zu erstellen:Does ServiceStack.OrmLite.JoinSqlBuilder erlauben eine einfache Abfrage zu bauen

SELECT * FROM Table1 a 
    INNER JOIN Table2 b ON ... 
    WHERE a.Column1 = 1 AND (a.Column2 = 2 OR b.Column3 = 3); 

Das Problem ist (a.Column2 = 2 OR b.Column3 = 3) Teil zu bauen. JoinSqlBuilder verfügt über eine Liste mit Methoden wie Where<T>, And<T>, Or<T>, mit denen Bedingungen für eine Abfrage hinzugefügt werden können.

Zum Beispiel, wenn ich tun:

builder 
    .Join(...) 
    .Where<Table1Poco>(a => a.Column1 == 1) 
    .And<Table1Poco>(a => a.Column2 == 2) 
    .Or<Table2Poco>(a => a.Column3 == 3) 
    ...; 

ich bekommen:

... WHERE a.Column1 = 1 AND a.Column2 = 2 OR b.Column3 = 3; 

Gibt es eine Möglichkeit a.Column1 = 1 AND (a.Column2 = 2 OR b.Column3 = 3) mit ServiceStack.OrmLite zu bauen?

Ich weiß, dass ich es mit rohen sql tun kann, aber es ist keine Option, wie ich Typsicherheit und Dialektunabhängigkeit nicht verlieren möchte.

+1

Soweit ich weiß, ist es nicht da. Und Micro-Orm ist gut für diese Art oder Dinge. Sie können auf einfache alte Abfragen für komplizierte Szenarien zurückgreifen. Hoffentlich kennen Sie die Abfrage () Funktion, die Sie verwenden können und einen Parameter übergeben, wenn Sie möchten. – kunjee

Antwort

4

Ich stimme Kunjee zu, dass dies nicht wirklich etwas ist, für das ein Micro-Orm gut ist. Nachdem ich das gesagt habe, kann ich mir zwei mögliche Optionen vorstellen ... von denen ich nicht wirklich etwas empfehlen würde, das ich über ein vollwertiges ORM (EF oder nHibernate) als Lösung empfehlen würde. Aber vielleicht hilft dies, bessere Optionen zu finden.

Option 1 - Erstellen Sie eine 'Where clause string' mit Reflektion, um eine gewisse 'type safety' zu erhalten. Sie müssen noch ein wenig SQL schreiben.

Beispiel

var jn = new JoinSqlBuilder<Table1, Table2>(); 
jn = jn.Join<Table1, Table2>(s => s.Column1, d => d.Field1); 

//using ExpressionVisitor because I didn't see a way to allow a Where clause string parameter to be used 
//on a JoinSqlBuilder method 
var ev = OrmLiteConfig.DialectProvider.ExpressionVisitor<Table1>(); 
ev.Where(
    SqlHelper.ToSqlField<Table1>(x => x.Column1) + "={0} AND (" + 
    SqlHelper.ToSqlField<Table1>(x => x.Column2) + "={1} OR " + SqlHelper.ToSqlField<Table2>(x => x.Column3) + 
     "={2})", "1", "2", "3"); 

var sql = jn.ToSql() + ev.WhereExpression; 

Helper Klasse

public static class SqlHelper 
{ 
    public static string ToSqlField<T>(Expression<Func<T, object>> expression) 
    { 
     //This should return something like 'Table1.Column1' 
     return typeof(T).Name + "." + GetMemberInfo(expression).Name; 
    } 

    // Stolen from FluentNHibernate.ReflectionUtility 
    public static MemberInfo GetMemberInfo<TEntity>(Expression<Func<TEntity, object>> expression) 
    { 
     MemberInfo memberInfo = null; 

     switch (expression.Body.NodeType) 
     { 
      case ExpressionType.Convert: 
       { 
        var body = (UnaryExpression)expression.Body; 
        if (body.Operand is MethodCallExpression) 
        { 
         memberInfo = ((MethodCallExpression)body.Operand).Method; 
        } 
        else if (body.Operand is MemberExpression) 
        { 
         memberInfo = ((MemberExpression)body.Operand).Member; 
        } 
       } 
       break; 
      case ExpressionType.MemberAccess: 
       memberInfo = ((MemberExpression)expression.Body).Member; 
       break; 
      default: 
       throw new ArgumentException("Unsupported ExpressionType", "expression"); 
     } 

     if (memberInfo == null) { throw new ArgumentException("Could not locate MemberInfo.", "expression"); } 

     return memberInfo; 
    } 
} 

Option 2 - Mess/Verunreinigen Ihre Klassen und ausschalten Tabelle Präfixe in einem Expression die richtige SQL zu ermöglichen, zu sein erzeugt. Dies wird völlig in die Luft gehen, wenn 2 Klassen dieselbe Eigenschaft haben und in einer Where-Klausel verwendet werden.

//Modify Table1 to include a reference to Table2 
public class Table1 
{ 
    public string Column1 { get; set; } 
    public string Column2 { get; set; } 

    [ServiceStack.DataAnnotations.Ignore] 
    public Table2 Table2 { get; set; } 
} 

var ev = OrmLiteConfig.DialectProvider.ExpressionVisitor<Table1>(); 
ev.PrefixFieldWithTableName = false; 

var jn = new JoinSqlBuilder<Table1, Table2>(); 
jn = jn.Join<Table1, Table2>(s => s.Column1, d => d.Field1); 
ev.Where(x => x.Column1 == "1"); 
ev.Where(x => x.Column2 == "2" || ((Table2)x.Table2).Column3 == "3"); //do cast to avoid InvalidOperationException 

var sql = jn.ToSql() + ev.WhereExpression; 
+0

Vielen Dank für eine vollständige Antwort. Ich bin zu sth ähnlich zu Option 1 gekommen - um meinen eigenen Abfragegenerator über OrmLites ExpressionVisitor zu schreiben. Ich stimme nicht zu, dass Joins keine Aufgabe für Micro-Orms sein sollten, da Joins in relationalen Datenbanken selbst das Kernstück sind. Ich habe hier keine sehr komplexe Verbindung. Die erste Sache, die ich von Orm will, ist vollständige Dialektunabhängigkeit, also ist rohe sql keine Wahl. Die zweite ist möglich (aber nicht erforderlich) Typsicherheit. Der zweite Punkt betrifft nur die Verwaltung von DTOs. Es ist nur eine Meinung. Danke nochmal für eine Antwort. – ILya

Verwandte Themen