1

NHibernate を介してやり取りするデータベース テーブルの一部には、次の構造を持つ XML フィールドが含まれています。

<L xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
   <I>
     <C>
       <N>Attribute1</N>
       <V>a_value</V>
     </C>
     <C>
       <N>Attribute2</N>
       <V>123</V>
     </C>
  </I>
</L>

基本的に、各「C」タグには属性が含まれており、その名前はタグ「N」に含まれ、値はタグ「V」に含まれています。

私が達成したいのは、クエリでこの種の LINQ 構文を記述できるようにすることです。

..
.Where(m=>m.XMLField(attribute_name, attribute_value))
..

「 attribute_value」で指定された文字列値を持つ「 attribute_name 」という名前の属性が XML フィールドに含まれている特定のテーブルのエンティティを取得できるようにします。

それと同じくらい単純です。XML 構造は常にそのようなものであり、特定の値を持つ単一の属性を照会するだけで済みます。

検索を行うと、カスタム LINQ プロバイダーを実装するための特定の手法があることがわかりました。

  1. http://www.primordialcode.com/blog/post/nhibernate-3-extending-linq-provider-fix-notsupported例外
  2. http://fabiomaulo.blogspot.it/2010/07/nhibernate-linq-provider-extension.html
  3. Linq-to-Nhibernate が特定の列に対して生成する SQL を変更するにはどうすればよいですか?

残念ながら、ツリービルダーの使用方法に関する構造化されたドキュメントを見つけることができなかったので、現時点ではこれが私が持っているものです:

このようなタスクを実行するための正しい HQL を見つけました。

where [some other statements] and XML_COLUMN_NAME.exist('/L/I/C[N=\"{0}\" and V=\"{1}\"]') = 1","attribute_name", "attribute_value");

LINQ クエリ内で呼び出すメソッド:

public static bool AttributeExists(this string xmlColumnName, string attributeName, string attributeValue)
{
   throw new NotSupportedException();
}

HQL との統合部分:

public class XMLAttributeGenerator : BaseHqlGeneratorForMethod
{
   public XMLAttributeGenerator()
   {
       SupportedMethods = new[] { ReflectionHelper.GetMethodDefinition(() => TestClass.AttributeExists(null, null, null)) };
   }

    public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject,
        ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
    {
        return treeBuilder.Exists(???);
    }
}

ご覧のとおり、ツリービルダーを訪問者オブジェクトと共に適切に使用して、上記の HQL 構文を複製する方法をまだ理解していません。誰かがこれで私を助けてくれますか、少なくともツリービルダーの使用法に関するいくつかの基本的なドキュメントを教えてくれますか? ありがとう

4

1 に答える 1

0

これが私が望ましい結果を達成した方法です:

モック法

public static class MockLINQMethods
    {
        public static bool XMLContains(this MyCustomNHType input, string element, string value)
        {
            throw new NotImplementedException();
        }
}

カスタムジェネレーター

public class CustomLinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
    {
        public CustomLinqToHqlGeneratorsRegistry()
            : base()
        {
            RegisterGenerator(ReflectionHelper.GetMethod(() => MockLINQMethods.XMLContains((MyCustomNHType) null, null, null)),
                              new LINQtoHQLGenerators.MyCustomNHTypeXMLContainsGenerator());
        }
}

public class MyCustomNHTypeXMLContainsGenerator : BaseHqlGeneratorForMethod
        {
            public MyCustomNHTypeXMLContainsGenerator()
            {
                SupportedMethods = new[] { ReflectionHelper.GetMethod(() => MockLINQMethods.XMLContains((MyCustomNHType) null, null, null)) };
            }

            public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject,
                ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
            {
                var column_name = visitor.Visit(arguments[0]).AsExpression();
                var element_name = visitor.Visit(arguments[1]).AsExpression();
                var value = visitor.Visit(arguments[2]).AsExpression();

                return treeBuilder.BooleanMethodCall("_ExistInMyCustomNHType", new [] { column_name, element_name, value});
            }
        }

カスタム機能

public class CustomLinqToHqlMsSql2008Dialect : MsSql2008Dialect
    {
        public CustomLinqToHqlMsSql2008Dialect()
        {
            RegisterFunction("_ExistInMyCustomNHType", 
                new SQLFunctionTemplate(NHibernateUtil.Boolean, 
                    "?1.exist('/L/I/C[N=sql:variable(\"?2\") and V=sql:variable(\"?3\")]') = 1"));
        }
    }

最後に、セッション ヘルパーでカスタム ジェネレーターとカスタム関数をリンクします。

    factory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008
    .ConnectionString(connectionString)
        .Dialect<CustomLinqToHqlMsSql2008Dialect>())
        ..
        .ExposeConfiguration(c =>
            {    
            ..         
            c.SetProperty("linqtohql.generatorsregistry", "APP.MyNAMESPACE.CustomLinqToHqlGeneratorsRegistry, APP.MyNAMESPACE");
            ..                        
            })                    
        .BuildSessionFactory();
于 2016-08-02T16:26:46.113 に答える