我正在尝试构建一个必须构建Case构造的自定义Hql生成器。此构造将在order by子句中使用。我试图按照当前用户的语言对枚举(在本例中为性别枚举)按字母顺序排序。如您所见,sortorder是从GenderResourceTextAttribute检索的。必须在Case构造中使用order数组中的值。这就是我到目前为止所做的:
public override HqlTreeNode BuildHql(MethodInfo method, System.Linq.Expressions.Expression targetObject, ReadOnlyCollection<System.Linq.Expressions.Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
GenderResourceTextAttribute attribute = null;
if (targetObject.Type.IsEnum)
{
attribute = targetObject.Type.GetCustomAttributes(typeof(GenderResourceTextAttribute), false).FirstOrDefault() as GenderResourceTextAttribute;
}
int[] order = attribute.GetSortOrderPosition();
return treeBuilder.Case(new HqlWhen(....));
}
[GenderResourceText]
public enum Gender
{
Unknown = 0,
Men,
Women
}
我最终希望它生成类似下面的sql:
case Gender when 0 then 1 when 1 then 2 else 0 end
我该如何实现?
编辑:根据Gerben的建议添加了我的解决方案:
谢谢Gerben!
通过您提供的示例,我能够完成它:
public override HqlTreeNode BuildHql(MethodInfo method, System.Linq.Expressions.Expression targetObject, ReadOnlyCollection<System.Linq.Expressions.Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
EnumResourceTextAttribute attribute = (EnumResourceTextAttribute)targetObject.Type.GetCustomAttributes(typeof(EnumResourceTextAttribute), false).FirstOrDefault();
IEnumerable<int> sortOrder = attribute.GetSortOrderPositions(arguments[0].ToString() == "Descending" ? System.Data.SqlClient.SortOrder.Descending : SortOrder.Ascending);
List<HqlExpression> parameters = new List<HqlExpression>();
List<HqlWhen> hqlWhenList = new List<HqlWhen>();
for(int index = 0; index < sortOrder.Count(); index++)
{
int position = sortOrder.ElementAt(index);
hqlWhenList.Add(
treeBuilder.When(
treeBuilder.Equality(visitor.Visit(targetObject).AsExpression(), treeBuilder.Constant(index)),
treeBuilder.Constant(position)
)
);
}
HqlCase hqlCase = treeBuilder.Case(hqlWhenList.ToArray());
return hqlCase;
}
答案 0 :(得分:2)
我的BuildHql方法如下所示。它使用了一个CaseBuilder,它包含在下面。
public override HqlTreeNode BuildHql(
MethodInfo method,
Expression targetObject,
ReadOnlyCollection<Expression> arguments,
HqlTreeBuilder treeBuilder,
IHqlExpressionVisitor visitor
)
{
// Get the CaseBuilder form the arguments.
var caseBuilder = (arguments[1] as ConstantExpression).Value as CaseBuilder;
var hqlWhenList = new List<HqlWhen>();
// Add a HqlWhen for each CaseBuilderOption.
foreach (var option in caseBuilder.Options)
{
// add the HqlWhen
hqlWhenList.Add(
// create HqlWhen with given treeBuilder.
treeBuilder.When(
// compare given property with the When of the CaseBuilderOption.
treeBuilder.Equality(visitor.Visit(arguments[0]).AsExpression(), treeBuilder.Constant(option.When)),
// add the Then value of the CaseBuilderOption
treeBuilder.Constant(option.Then)
)
);
}
//
return
// cast the returned value to returntype of CaseBuilder.
treeBuilder.Cast(
// create the HqlCase with the TreeBuilder.
treeBuilder.Case(
// add the created HqlWhen list.
hqlWhenList.ToArray(),
// add the final or else value from the CaseBuilder.
treeBuilder.Constant(caseBuilder.ElseValue)
),
// the return type for the cast.
caseBuilder.ReturnType
);
}
CaseBuilder和CaseBuilderOption类。
public class CaseBuilder
{
/// <summary>
/// The options of this case.
/// </summary>
public List<CaseBuilderOption> Options { get; set; }
/// <summary>
/// Else return value.
/// </summary>
public object ElseValue { get; set; }
/// <summary>
/// Type of return value.
/// </summary>
public Type ReturnType { get; set; }
/// <summary>
///
/// </summary>
/// <param name="returnType"></param>
/// <param name="case1"></param>
/// <param name="value1"></param>
/// <param name="elseValue"></param>
public CaseBuilder(Type returnType, object when, object then, object elseValue)
{
ReturnType = returnType;
if (then.GetType() != returnType || elseValue.GetType() != returnType)
{
throw new Exception();
}
Options = new List<CaseBuilderOption>();
Options.Add(new CaseBuilderOption() { When = when, Then = then });
ElseValue = elseValue;
}
/// <summary>
/// Add a WhenThen option to the case builder.
/// </summary>
/// <param name="when"></param>
/// <param name="then"></param>
/// <returns></returns>
public CaseBuilder Append(object when, object then)
{
if (then.GetType() != ReturnType)
{
throw new Exception();
}
Options.Add(new CaseBuilderOption() { When = when, Then = then });
return this;
}
}
/// <summary>
/// A When Then option of a Case
/// </summary>
public class CaseBuilderOption
{
/// <summary>
/// When
/// </summary>
public object When { get; set; }
/// <summary>
/// returns this value if When and Case property are equal
/// </summary>
public object Then { get; set; }
}
我希望这会对你有所帮助。