2013-06-26 6 views
6

を構築することを可能にする:んServiceStack.OrmLite.JoinSqlBuilder ServiceStack.OrmLiteのJoinSqlBuilderは、以下の単純なクエリを構築することを可能にする場合、私は思ったんだけど、単純なクエリ

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

問題が(a.Column2 = 2 OR b.Column3 = 3)部分を構築することです。 JoinSqlBuilderには、クエリの条件を追加できるメソッドのリスト(Where<T>, And<T>, Or<T>など)があります。例えば

私がしなければ、:

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

は私が取得します:

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

はServiceStack.OrmLiteでa.Column1 = 1 AND (a.Column2 = 2 OR b.Column3 = 3)を構築する方法はありますか?

私はraw SQLでそれを行うことができることを知っていますが、型の安全性と方言の独立性を失いたくないのでオプションではありません。

+1

私が知る限り、それはありません。そして、Micro-ormはこの種のものにはいいです。複雑なシナリオについては、古いクエリーに戻すことができます。うまくいけば、クエリ()関数を使用することができますし、必要に応じてパラメータを渡すことができます。 – kunjee

答えて

4

私はkunjeeに、これはMicro-ormが良いものではないことに同意します。これで、私は2つの可能性のある選択肢を考えることができます...どちらも、本当にORM(EFまたはnHibernate)をソリューションとして推奨するものではありません。しかし、これはもっと良い選択肢を求めるのに役立ちます。

オプション1 - 一部の 'タイプセーフティ'を維持するためにリフレクションを使用して 'Where句ストリング'を構築します。あなたはまだ少しのSQLを書く必要があります。

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; 

ヘルパークラス

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; 
    } 
} 

オプション2 - メス/正しいSQLができるようにするために、あなたのクラスを汚染し、ExpressionVisitorのテーブル接頭辞をオフにします生成される。 2つのクラスが同じプロパティを持ち、Where句で使用されている場合、これは完全に爆発します。

//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

完全な答えをありがとう。私はオプション1と同様に、OrmLiteのExpressionVisitor上に独自のクエリビルダーを書くようになった。私は、ジョインは実際にはリレーショナルデータベース自体の中核であるため、マイクロオームのためのタスクではないことに同意します。私はここで非常に複雑な結合を持っていない。 ormから最初に必要なことは、完全な方言の独立性であり、raw SQLはオプションではありません。第2のものは、タイプセーフである(しかし必須ではない)。第2のポイントは、DTOを管理することです。それはただの意見です。もう一度お返事ありがとうございます。 – ILya

関連する問題