2016-06-30 8 views
1

Некоторые из моих таблиц базы данных, которые я взаимодействующая с помощью NHibernate, содержать поле XML со следующей структурой:заказ поставщик LINQ для поиска в поле XML для атрибута 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)) 
.. 

, так что я смог получить объекты определенного таблицы, XML поле содержит атрибут «имя_источника» со строковым значением, указанным «attribute_value».

Это так просто, структура XML всегда такая, и мне нужно всего лишь запросить один атрибут с определенным значением.

Делая мои поиски, я нашел, что есть конкретный метод для реализации пользовательского поставщика LINQ:

  1. http://www.primordialcode.com/blog/post/nhibernate-3-extending-linq-provider-fix-notsupportedexception
  2. http://fabiomaulo.blogspot.it/2010/07/nhibernate-linq-provider-extension.html
  3. How would I alter the SQL that Linq-to-Nhibernate generates for specific columns?

К сожалению, я не был» t можно найти структурированную документацию о том, как использовать деревообразователь, так что на данный момент это то, что у меня есть:

я понял, правильно 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(???); 
    } 
} 

Как вы можете видеть, я до сих пор не понял, как правильно использовать treebuilder с объектом-посетителем для репликации синтаксиса HQL, выраженного выше. Может кто-нибудь помочь мне с этим или, по крайней мере, указать мне на некоторые базовые документы об использовании treebuilder?Благодаря

ответ

0

Это, как я достиг желаемого результата:

Мок МЕТОД

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

CUSTOM ГЕНЕРАТОР

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}); 
      } 
     } 

CUSTOM ФУНКЦИЯ

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")); 
     } 
    } 

Наконец, связать CUSTOM генератора и пользовательской функции в сеансе НЕЬРЕК

factory = Fluently.Configure() 
.Database(MsSqlConfiguration.MsSql2008 
    .ConnectionString(connectionString) 
     .Dialect<CustomLinqToHqlMsSql2008Dialect>()) 
     .. 
     .ExposeConfiguration(c => 
      {  
      ..   
      c.SetProperty("linqtohql.generatorsregistry", "APP.MyNAMESPACE.CustomLinqToHqlGeneratorsRegistry, APP.MyNAMESPACE"); 
      ..       
      })      
     .BuildSessionFactory();