Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Nhibernate在linq查询中转义特殊字符_C#_Sql_Linq_Nhibernate_Fluent Nhibernate - Fatal编程技术网

C# Nhibernate在linq查询中转义特殊字符

C# 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

我有一张像这样的桌子:

表格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>()
            .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", '\\'))