2016-06-30 7 views
1

Einige meiner Datenbanktabellen zu suchen, die mich mit durch NHibernate interagieren, enthält ein XML-Feld mit der folgenden Struktur: GrundsätzlichBenutzerdefinierte Linq-Anbieter in ein XML-Feld für ein XML-Attribut mit einem bestimmten Wert

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

Jedes "C" -Tag enthält ein Attribut, dessen Name im Tag "N" und sein Wert im Tag "V" enthalten ist.

Was ich erreichen möchte ist in der Lage zu sein, diese Art von LINQ-Syntax in meine Abfragen zu schreiben:

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

, so dass ich in der Lage, die Einheiten einer bestimmten Tabelle, deren XML-Feld zu erhalten enthält das Attribut "Attributname" mit dem Zeichenfolgenwert, der durch "attribute_value" angegeben wird.

So einfach ist das, die XML-Struktur ist immer so und ich muss nur ein einzelnes Attribut mit einem bestimmten Wert abfragen.

meine Suche Doing ich gefunden habe, dass es eine spezielle Technik ist eine benutzerdefinierte LINQ-Anbieter zu implementieren:

  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?

Leider war nicht ich‘ Ich bin in der Lage, eine strukturierte Dokumentation über die Verwendung des Treebuilders zu finden, also habe ich im Moment folgendes:

Ich habe die richtige HQL herausgefunden, eine solche Aufgabe zu erfüllen:

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

die Methode, die ich in der LINQ-Abfrage nennen werde:

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

die Integration Teil mit 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(???); 
    } 
} 

Wie Sie sehen, habe ich immer noch nicht herausgefunden, wie man den Baumerzeuger mit dem Besucherobjekt richtig verwendet, um die oben ausgedrückte HQL-Syntax zu replizieren. Kann mir jemand dabei helfen oder zumindest auf eine grundlegende Dokumentation über die Benutzung des Treebuilders hinweisen?Dank

Antwort

0

Dies ist, wie ich das gewünschte Ergebnis erreicht:

MOCK VERFAHREN

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

CUSTOM GENERATOR

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 FUNCTION

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

ENDLICH Link, um die CUSTOM Generator und die benutzerdefinierte Funktion in der Sitzung HELFER

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