C# Nhibernate在linq查询中转义特殊字符
我有一张像这样的桌子: 表格XYC# Nhibernate在linq查询中转义特殊字符,c#,sql,linq,nhibernate,fluent-nhibernate,C#,Sql,Linq,Nhibernate,Fluent Nhibernate,我有一张像这样的桌子: 表格XY |ID |SOURCE| |1 |value_aa| |2 |other_aa| |3 |eeeaa| 生成的查询应该是: select * from TABLE_XY where SOURCE like '%\_aa' ESCAPE '\' 我知道有两种选择适合我的需要 var result = session.QueryOver<TableXy>() .WhereRestricti
|ID |SOURCE|
|1 |value_aa|
|2 |other_aa|
|3 |eeeaa|
生成的查询应该是:
select * from TABLE_XY where SOURCE like '%\_aa' ESCAPE '\'
我知道有两种选择适合我的需要
var result =
session.QueryOver<TableXy>()
.WhereRestrictionOn(x => x.Source)
.IsLike("%\_aa", MatchMode.Exact, '\\')
.List();
这里的解决方案应该非常简单:
var result = session
.Query<TableXy>()
// instead of this
//.Where(x => NHibernate.Linq.SqlMethods.Like(x.Source, "%\\_aa"))
// This will add sign % at the beginning only
.Where(x => x.Source.EndsWith("[_]aa"));
// or wrap it on both sides with sign: %
.Where(x => x.Source.Contains("[_]aa"));
.ToList();
var结果=会话
.Query()
//而不是这个
//.Where(x=>NHibernate.Linq.SqlMethods.Like(x.Source,“%\\\\\u aa”))
//这将仅在开头添加符号%
其中(x=>x.Source.EndsWith(“[[u]aa”);
//或用标志%
其中(x=>x.Source.Contains(“[]aa”);
.ToList();
诀窍是对下划线使用类似ruglar的表达式样式
[\u]
好的,这是一个非常复杂的答案,可能会有很多问题,但我能够得到一个类似的操作符,带有一个转义工件
这涉及到几个步骤,但基本上我们正在做的是添加一种新类型的HqlTreeNode
,它可以处理like
操作符的escape
部分
创建将在LINQ查询中使用的扩展方法。此方法不需要实现--我们将在后面提供:
public static class LinqExtensions
{
public static bool IsLikeWithEscapeChar(
this string input,
string like,
char? escapeChar)
{
throw new NotImplementedException();
}
}
创建一个hqlesce
树节点,我们将使用它来表示like
操作符的escape
部分:
public class HqlEscape : HqlExpression
{
public HqlEscape(IASTFactory factory, params HqlTreeNode[] children)
: base(HqlSqlWalker.ESCAPE, "escape", factory, children)
{
}
}
创建一个类似于视图的hql
树节点。默认的hqlike
节点无法处理escape
部分,因此我们需要创建一个可以处理三个子节点的新节点:
public class HqlLikeWithEscape : HqlBooleanExpression
{
public HqlLikeWithEscape(IASTFactory factory, HqlExpression lhs, HqlExpression rhs, HqlEscape escape)
: base(HqlSqlWalker.LIKE, "like", factory, lhs, rhs, escape)
{
}
}
为前面定义的IsLikeWithEscapeChar
扩展方法创建一个生成器。此类的职责是获取调用该方法的信息,并返回最终将转换为SQL的HQL树结构:
public class CustomLikeGenerator : BaseHqlGeneratorForMethod
{
public CustomLikeGenerator()
{
this.SupportedMethods = new[]
{
ReflectionHelper.GetMethodDefinition(
() => LinqExtensions.IsLikeWithEscapeChar(null, null, null))
};
}
public override HqlTreeNode BuildHql(
MethodInfo method,
System.Linq.Expressions.Expression targetObject,
ReadOnlyCollection<System.Linq.Expressions.Expression> arguments,
HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
// Is there a better way to do this?
var factory = new ASTFactory(new ASTTreeAdaptor());
HqlTreeNode escapeCharNode = visitor.Visit(arguments[2]).AsExpression();
var escapeNode = new HqlEscape(factory, escapeCharNode);
HqlLikeWithEscape likeClauseNode =
new HqlLikeWithEscape(
factory,
visitor.Visit(arguments[0]).AsExpression(),
visitor.Visit(arguments[1]).AsExpression(),
escapeNode);
return likeClauseNode;
}
}
更新配置以使用新的LinqToHqlGeneratorsRegistry
:
cfg.LinqToHqlGeneratorsRegistry<LinqToHqlGeneratorsRegistry>();
cfg.LinqToHqlGeneratorsRegistry();
(最后)在查询中使用新的扩展方法:
session.Query<Person>().Where(p => p.FirstName.IsLikeWithEscapeChar("%Foo", '\\'))
session.Query().Where(p=>p.FirstName.IsLikeWithEscapeChar(“%Foo”,“\\”)
请注意,您需要指定通配符。这是可以解决的,但这并不难做到
这是我第一次以这种方式扩展HQL,所以这个解决方案可能会出现问题。我只能够在SQL Server上进行测试,但我有理由相信它应该可以工作,因为它创建的树结构与HQL查询相同。这个解决方案适用于MS-SQL,但不适用于Oracle数据库。很可能是的。。。MS SQL server确实支持这样的正则表达式。对但老实说,没有这样的经验与甲骨文。。。很抱歉但是您仍然可以使用诸如EndsWith()
,StartsWith()
,Contains()
。。。并传递类似Oracle的样式表达式。应该是这样的……不,遗憾的是,当我执行类似于Contains(“%\u aa”)的操作时,这将返回值“val\u aa”和“valaa”。这是错误的。如果我确实包含(“%\\u aa”),则不会返回任何内容。我需要以某种方式将转义字符传递给服务器我无法测试Oracle,但这可以/应该可以工作.EndsWith(@“\u aa”)
(也适用于SQL Server)。遗憾的是,这种方法返回的条目太多,因为“\u”将被解释为任何字符,因此“\u aa”或“1aa”或“Xaa”也将符合标准!你的解决方案如我所料有效!我所做的唯一更改是:我没有创建新的ASTFactory,而是这样做var factory=treeBuilder.Constant(null).factory
来获取内部工厂。我不知道这是否100%正确,但它是有效的
public class CustomLikeGenerator : BaseHqlGeneratorForMethod
{
public CustomLikeGenerator()
{
this.SupportedMethods = new[]
{
ReflectionHelper.GetMethodDefinition(
() => LinqExtensions.IsLikeWithEscapeChar(null, null, null))
};
}
public override HqlTreeNode BuildHql(
MethodInfo method,
System.Linq.Expressions.Expression targetObject,
ReadOnlyCollection<System.Linq.Expressions.Expression> arguments,
HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
// Is there a better way to do this?
var factory = new ASTFactory(new ASTTreeAdaptor());
HqlTreeNode escapeCharNode = visitor.Visit(arguments[2]).AsExpression();
var escapeNode = new HqlEscape(factory, escapeCharNode);
HqlLikeWithEscape likeClauseNode =
new HqlLikeWithEscape(
factory,
visitor.Visit(arguments[0]).AsExpression(),
visitor.Visit(arguments[1]).AsExpression(),
escapeNode);
return likeClauseNode;
}
}
public class LinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
{
public LinqToHqlGeneratorsRegistry() : base()
{
RegisterGenerator(
ReflectionHelper.GetMethodDefinition(() => LinqExtensions.IsLikeWithEscapeChar(null, null, null)),
new CustomLikeGenerator());
}
}
cfg.LinqToHqlGeneratorsRegistry<LinqToHqlGeneratorsRegistry>();
session.Query<Person>().Where(p => p.FirstName.IsLikeWithEscapeChar("%Foo", '\\'))