[英]Custom linq provider to search into an XML field for an xml attribute with a certain value
我通過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))
..
這樣我就能得到一個特定表的實體,其XML字段包含名為“ attribute_name ”的屬性 ,其字符串值由“ attribute_value ”指定。
就這么簡單,XML結構總是這樣,我只需要查詢具有特定值的單個屬性。
做我的搜索我發現有一種特定的技術來實現自定義LINQ提供程序:
不幸的是,我無法找到關於如何使用treebuilder的結構化文檔,因此,目前這就是我所擁有的:
我已經找到了正確的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和visitor對象來復制上面表達的HQL語法。 可能有人幫我解決這個問題,或者至少指出一些關於treebuilder使用的基本文檔? 謝謝
這就是我實現預期結果的方式:
模塊法
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();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.