2016-12-05 16 views
0

なんらかの理由で、Linq Expression(where句のみ)&とHQL where句を1つのクエリに組み合わせる必要があります。Linq Expression where節をhql where節に翻訳するには?

私は、session.Query<T>() APIがLinq ExpressionをHqlQueryオブジェクト(それはHqlExpressionに拡張)に変換することがわかりました。

Linq Expression where句をHQL where句queryStringに変換するにはどうすればいいですか?次に、別のHQL Where句where queryStringを新しいクエリに組み合わせることはできますか?

+1

LINQ式を 'HqlExpression'にどのように翻訳していますか?私が見つけた最高のものはFluentNHibernateの 'ExpressionToSql.Convert (e => e.Id> 0)'でした。 –

+0

ありがとうございます。最後に、自分でそれを実装しました。私の答えで見ることができます。 – shine

答えて

1

使用できないようですが、Linqの式をHQLツリーに変換するためのNHibernate APIがあります。 Linq式から生成されたHQLツリーは、実際のHQLクエリとは逆のものではありません。

だから私は自分でHQLにLINQの式を変換する必要があります。

var expr = GetExpr<Ninja>(x => 
    x.Age > 1 && x.Country.Name == "中国" 
    || 
    (x.Id > 10 && x.Country.Name == "中国") 
); 

var translator = new ExpressionToHqlTranslator("_this"); 
translator.Translate(expr); 
Console.WriteLine(translator.WhereClause); 
Console.WriteLine(translator.Patameters); 

==============結果を============ =

WhereClause: (((_this.Age > ?) AND (_this.Country.Name = ?)) OR ((_this.Id > ?) AND (_this.Country.Name = ?))) 

Patameters:4 

===============クリティカルコード=============

static Expression<Func<T, object>> GetExpr<T>(Expression<Func<T, object>> expr){ 
    eturn expr; 
} 


using System; 
using System.Linq; 
using NHibernate.Linq; 
using NHibernate.Linq.Visitors; 
using System.Linq.Expressions; 
using NHibernate; 
using System.Text; 
using System.Collections.Generic; 

namespace Rhythm.Linq 
{ 
    public class ExpressionToHqlTranslator : System.Linq.Expressions.ExpressionVisitor 
    { 
     private StringBuilder sb; 
     private string _orderBy = ""; 
     private int? _skip = null; 
     private int? _take = null; 
     private string _whereClause = ""; 
     List<object> patameters; 

     public int? Skip 
     { 
      get 
      { 
       return _skip; 
      } 
     } 

     public int? Take 
     { 
      get 
      { 
       return _take; 
      } 
     } 

     public string OrderBy 
     { 
      get 
      { 
       return _orderBy; 
      } 
     } 

     public string WhereClause 
     { 
      get 
      { 
       return _whereClause; 
      } 
     } 

     public List<object> Patameters 
     { 
      get 
      { 
       return patameters; 
      } 

      set 
      { 
       patameters = value; 
      } 
     } 

     string prefix; 
     public ExpressionToHqlTranslator(string prefix = null) 
     { 
      this.prefix = string.IsNullOrEmpty(prefix) ? null : (prefix + "."); 
     } 

     public string Translate(Expression expression) 
     { 
      this.sb = new StringBuilder(); 
      this.patameters = new List<object>(); 
      this.Visit(expression); 
      _whereClause = this.sb.ToString(); 
      return _whereClause; 
     } 

     private static Expression StripQuotes(Expression e) 
     { 
      while (e.NodeType == ExpressionType.Quote) 
      { 
       e = ((UnaryExpression)e).Operand; 
      } 
      return e; 
     } 

     protected override Expression VisitMethodCall(MethodCallExpression m) 
     { 
      if (m.Method.DeclaringType == typeof(Queryable) && m.Method.Name == "Where") 
      { 
       this.Visit(m.Arguments[0]); 
       LambdaExpression lambda = (LambdaExpression)StripQuotes(m.Arguments[1]); 
       this.Visit(lambda.Body); 
       return m; 
      } 
      else if (m.Method.Name == "Take") 
      { 
       if (this.ParseTakeExpression(m)) 
       { 
        Expression nextExpression = m.Arguments[0]; 
        return this.Visit(nextExpression); 
       } 
      } 
      else if (m.Method.Name == "Skip") 
      { 
       if (this.ParseSkipExpression(m)) 
       { 
        Expression nextExpression = m.Arguments[0]; 
        return this.Visit(nextExpression); 
       } 
      } 
      else if (m.Method.Name == "OrderBy") 
      { 
       if (this.ParseOrderByExpression(m, "ASC")) 
       { 
        Expression nextExpression = m.Arguments[0]; 
        return this.Visit(nextExpression); 
       } 
      } 
      else if (m.Method.Name == "OrderByDescending") 
      { 
       if (this.ParseOrderByExpression(m, "DESC")) 
       { 
        Expression nextExpression = m.Arguments[0]; 
        return this.Visit(nextExpression); 
       } 
      } 

      throw new NotSupportedException(string.Format("The method '{0}' is not supported", m.Method.Name)); 
     } 

     protected override Expression VisitUnary(UnaryExpression u) 
     { 
      switch (u.NodeType) 
      { 
       case ExpressionType.Not: 
        sb.Append(" NOT "); 
        this.Visit(u.Operand); 
        break; 
       case ExpressionType.Convert: 
        this.Visit(u.Operand); 
        break; 
       default: 
        throw new NotSupportedException(string.Format("The unary operator '{0}' is not supported", u.NodeType)); 
      } 
      return u; 
     } 


     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="b"></param> 
     /// <returns></returns> 
     protected override Expression VisitBinary(BinaryExpression b) 
     { 
      sb.Append("("); 
      this.Visit(b.Left); 

      switch (b.NodeType) 
      { 
       case ExpressionType.And: 
        sb.Append(" AND "); 
        break; 

       case ExpressionType.AndAlso: 
        sb.Append(" AND "); 
        break; 

       case ExpressionType.Or: 
        sb.Append(" OR "); 
        break; 

       case ExpressionType.OrElse: 
        sb.Append(" OR "); 
        break; 

       case ExpressionType.Equal: 
        if (IsNullConstant(b.Right)) 
        { 
         sb.Append(" IS "); 
        } 
        else 
        { 
         sb.Append(" = "); 
        } 
        break; 

       case ExpressionType.NotEqual: 
        if (IsNullConstant(b.Right)) 
        { 
         sb.Append(" IS NOT "); 
        } 
        else 
        { 
         sb.Append(" <> "); 
        } 
        break; 

       case ExpressionType.LessThan: 
        sb.Append(" < "); 
        break; 

       case ExpressionType.LessThanOrEqual: 
        sb.Append(" <= "); 
        break; 

       case ExpressionType.GreaterThan: 
        sb.Append(" > "); 
        break; 

       case ExpressionType.GreaterThanOrEqual: 
        sb.Append(" >= "); 
        break; 

       default: 
        throw new NotSupportedException(string.Format("The binary operator '{0}' is not supported", b.NodeType)); 

      } 

      this.Visit(b.Right); 
      sb.Append(")"); 
      return b; 
     } 


     protected override Expression VisitConstant(ConstantExpression c) 
     { 
      this.patameters.Add(c.Value); 
      sb.Append('?'); 
      //IQueryable q = c.Value as IQueryable; 

      //if (q == null && c.Value == null) 
      //{ 
      // sb.Append("NULL"); 
      //} 
      //else if (q == null) 
      //{ 
      // switch (Type.GetTypeCode(c.Value.GetType())) 
      // { 
      //  case TypeCode.Boolean: 
      //   sb.Append(((bool)c.Value) ? 1 : 0); 
      //   break; 

      //  case TypeCode.String: 
      //   sb.Append("'"); 
      //   sb.Append(c.Value); 
      //   sb.Append("'"); 
      //   break; 

      //  case TypeCode.DateTime: 
      //   sb.Append("'"); 
      //   sb.Append(c.Value); 
      //   sb.Append("'"); 
      //   break; 

      //  case TypeCode.Object: 
      //   throw new NotSupportedException(string.Format("The constant for '{0}' is not supported", c.Value)); 

      //  default: 
      //   sb.Append(c.Value); 
      //   break; 
      // } 
      //} 

      return c; 
     } 

     protected override Expression VisitMember(MemberExpression m) 
     { 
      if (this.prefix != null) 
      { 
       sb.Append(this.prefix); 
      } 
      sb.Append(ContactModelPropertyVistHierarchyExpression(m, m.Member.DeclaringType)); 
      //if (m.Expression != null && m.Expression.NodeType == ExpressionType.Parameter) 
      //{ 
      // sb.Append(m.Member.Name); 
      // return m; 
      //} 
      return m; 

      //throw new NotSupportedException(string.Format("The member '{0}' is not supported", m.Member.Name)); 
     } 

     protected bool IsNullConstant(Expression exp) 
     { 
      return (exp.NodeType == ExpressionType.Constant && ((ConstantExpression)exp).Value == null); 
     } 

     private bool ParseOrderByExpression(MethodCallExpression expression, string order) 
     { 
      UnaryExpression unary = (UnaryExpression)expression.Arguments[1]; 
      LambdaExpression lambdaExpression = (LambdaExpression)unary.Operand; 

      lambdaExpression = (LambdaExpression)NHibernate.Linq.Visitors.Evaluator.PartialEval(lambdaExpression); 

      MemberExpression body = lambdaExpression.Body as MemberExpression; 
      if (body != null) 
      { 
       if (string.IsNullOrEmpty(_orderBy)) 
       { 
        _orderBy = string.Format("{0} {1}", body.Member.Name, order); 
       } 
       else 
       { 
        _orderBy = string.Format("{0}, {1} {2}", _orderBy, body.Member.Name, order); 
       } 

       return true; 
      } 

      return false; 
     } 

     private bool ParseTakeExpression(MethodCallExpression expression) 
     { 
      ConstantExpression sizeExpression = (ConstantExpression)expression.Arguments[1]; 

      int size; 
      if (int.TryParse(sizeExpression.Value.ToString(), out size)) 
      { 
       _take = size; 
       return true; 
      } 

      return false; 
     } 

     private bool ParseSkipExpression(MethodCallExpression expression) 
     { 
      ConstantExpression sizeExpression = (ConstantExpression)expression.Arguments[1]; 

      int size; 
      if (int.TryParse(sizeExpression.Value.ToString(), out size)) 
      { 
       _skip = size; 
       return true; 
      } 

      return false; 
     } 
    } 


    public static string ContactModelPropertyVistHierarchyExpression(Expression expr, Type modelType) 
    { 
      StringBuilder sb = new StringBuilder(); 
      Expression curr = expr; 
      // TypedParameterExpression 
      while (curr != null) 
      { 
       if (curr is MemberExpression) 
       { 
        var x = curr as MemberExpression; 
        sb.Insert(0, x.Member.Name); 
        curr = x.Expression; 
       } 
       else if (curr is MethodCallExpression) 
       { 
        var x = curr as MethodCallExpression; 
        sb.Insert(0, x.Method.Name); 
        curr = x.Object; 
       } 
       else if (curr is ParameterExpression) 
       { 
        break; 
       } 
       else 
       { 
        throw new ArgumentException("Unsupported Expression type " + curr.GetType().FullName + " for expression " + expr.ToString(), "expr"); 
       } 
       sb.Insert(0, '.'); 
      } 
      return sb.Length > 1 ? sb.Remove(0, 1).ToString() : sb.ToString(); 
    } 
} 

DLL参照NHibernateはを追加.Linq.dll

+0

Evaluatorクラスとは何ですか? –

+1

NHibernate.Linq.Visitors.Evaluator from NHibernate.Linq.dll – shine

+0

NHibernate.Linq.dllは何年も前に廃止されました。 –