使用できないようですが、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
LINQ式を 'HqlExpression'にどのように翻訳していますか?私が見つけた最高のものはFluentNHibernateの 'ExpressionToSql.Convert(e => e.Id> 0)'でした。 –
ありがとうございます。最後に、自分でそれを実装しました。私の答えで見ることができます。 – shine