我可以不使用 where 子句创建自定义表达式吗?
Can I create a custom expression without using the where clause?
虽然我已经在上一个问题中使用原生查询解决了这个问题。我现在想知道是否可以在不使用 where 子句的情况下创建可在 Criteria 中使用的自定义表达式?我不想要 where 子句的原因是 Oracle 的 connect by ... start with ... (here) 语句。我按照这个页面开始我的工作。但是,这将生成类似 select * from foo where connect by start with...
的代码
这是我正在使用的。查看生成的内容,我可以说它正在生成正确的语句减去 where 子句。
public class StartWithConnectByCriteria : AbstractCriterion
{
public StartWithConnectByCriteria(string parentName, string parentValue, string childName)
{
ParentName = parentName;
ParentValue = parentValue;
ChildName = childName;
}
public string ParentName { get; set; }
public string ParentValue { get; set; }
public string ChildName { get; set; }
public IProjection P { get; set; }
public override IProjection[] GetProjections()
{
if(P != null)
{
return new IProjection[] {P};
}
return null;
}
public override TypedValue[] GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
return
CriterionUtil.GetTypedValues(criteriaQuery, criteria, P, ParentName, ParentValue.ToString());
}
public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery,
IDictionary<string, IFilter> enabledFilters)
{
var sqlBuilder = new SqlStringBuilder();
SqlString[] parentColumnNames = CriterionUtil.GetColumnNames(ParentName,
P, criteriaQuery,
criteria, enabledFilters);
SqlString parentColumnName = parentColumnNames[0];
SqlString[] childColumnNames = CriterionUtil.GetColumnNames(ChildName,
P, criteriaQuery,
criteria, enabledFilters);
SqlString childColumnName = childColumnNames[0];
criteriaQuery.AddUsedTypedValues(GetTypedValues(criteria, criteriaQuery));
sqlBuilder
.Add("start with" + parentColumnName +" = '" + ParentValue +"'")
.Add(" connect by prior" + childColumnName +" =" + parentColumnName);
return sqlBuilder.ToSqlString();
}
public override string ToString()
{
return"";
}
}StartWithConnectByCriteria criterion =
new StartWithConnectByCriteria(
"parent",
"parent_value",
"child");
DetachedCriteria dc = DetachedCriteria.For<NormalUpstream>("nu")
.Add(criterion);select
random_column
from
table
start with parent_id = 'parent_node_id'
connect by prior child_up_id = parent_id
我就是这样用的。
public class StartWithConnectByCriteria : AbstractCriterion
{
public StartWithConnectByCriteria(string parentName, string parentValue, string childName)
{
ParentName = parentName;
ParentValue = parentValue;
ChildName = childName;
}
public string ParentName { get; set; }
public string ParentValue { get; set; }
public string ChildName { get; set; }
public IProjection P { get; set; }
public override IProjection[] GetProjections()
{
if(P != null)
{
return new IProjection[] {P};
}
return null;
}
public override TypedValue[] GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
return
CriterionUtil.GetTypedValues(criteriaQuery, criteria, P, ParentName, ParentValue.ToString());
}
public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery,
IDictionary<string, IFilter> enabledFilters)
{
var sqlBuilder = new SqlStringBuilder();
SqlString[] parentColumnNames = CriterionUtil.GetColumnNames(ParentName,
P, criteriaQuery,
criteria, enabledFilters);
SqlString parentColumnName = parentColumnNames[0];
SqlString[] childColumnNames = CriterionUtil.GetColumnNames(ChildName,
P, criteriaQuery,
criteria, enabledFilters);
SqlString childColumnName = childColumnNames[0];
criteriaQuery.AddUsedTypedValues(GetTypedValues(criteria, criteriaQuery));
sqlBuilder
.Add("start with" + parentColumnName +" = '" + ParentValue +"'")
.Add(" connect by prior" + childColumnName +" =" + parentColumnName);
return sqlBuilder.ToSqlString();
}
public override string ToString()
{
return"";
}
}StartWithConnectByCriteria criterion =
new StartWithConnectByCriteria(
"parent",
"parent_value",
"child");
DetachedCriteria dc = DetachedCriteria.For<NormalUpstream>("nu")
.Add(criterion);select
random_column
from
table
start with parent_id = 'parent_node_id'
connect by prior child_up_id = parent_id
我感觉它与 DetachedCriteria 中的 .Add() 有关,但不是 100% 不幸的是,我似乎找不到太多关于创建自定义表达式的文档。
编辑:现在我想起来好像我在叫错树了。虽然这并不重要(我已经有了一个不错的实现)。我仍然有兴趣了解如何进一步自定义 NHibernate。
编辑 2:由于开箱即用的 NHibernate 不支持 Oracle 的专有功能,start with ... connect by。我试图通过添加对 NHibernate 的原生支持来了解更多关于扩展 NHibernate 的信息。我知道我可以使用自定义方言注册这些功能。但我想知道是否可以将它作为标准来实现,以便我可以将它与我的其他标准查询一起使用。我发布的代码工作正常并且正确地创建了有效的 SQL,但是当我将 StartWithConnectByCriteria 添加到我的条件时,NHibernate 将发出一个查询,例如 select this_.id from table where start with ... connect by。这是一个无效的查询,因为该子句不属于 where.
这是我希望 NHibernate 生成的查询。
public class StartWithConnectByCriteria : AbstractCriterion
{
public StartWithConnectByCriteria(string parentName, string parentValue, string childName)
{
ParentName = parentName;
ParentValue = parentValue;
ChildName = childName;
}
public string ParentName { get; set; }
public string ParentValue { get; set; }
public string ChildName { get; set; }
public IProjection P { get; set; }
public override IProjection[] GetProjections()
{
if(P != null)
{
return new IProjection[] {P};
}
return null;
}
public override TypedValue[] GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
return
CriterionUtil.GetTypedValues(criteriaQuery, criteria, P, ParentName, ParentValue.ToString());
}
public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery,
IDictionary<string, IFilter> enabledFilters)
{
var sqlBuilder = new SqlStringBuilder();
SqlString[] parentColumnNames = CriterionUtil.GetColumnNames(ParentName,
P, criteriaQuery,
criteria, enabledFilters);
SqlString parentColumnName = parentColumnNames[0];
SqlString[] childColumnNames = CriterionUtil.GetColumnNames(ChildName,
P, criteriaQuery,
criteria, enabledFilters);
SqlString childColumnName = childColumnNames[0];
criteriaQuery.AddUsedTypedValues(GetTypedValues(criteria, criteriaQuery));
sqlBuilder
.Add("start with" + parentColumnName +" = '" + ParentValue +"'")
.Add(" connect by prior" + childColumnName +" =" + parentColumnName);
return sqlBuilder.ToSqlString();
}
public override string ToString()
{
return"";
}
}StartWithConnectByCriteria criterion =
new StartWithConnectByCriteria(
"parent",
"parent_value",
"child");
DetachedCriteria dc = DetachedCriteria.For<NormalUpstream>("nu")
.Add(criterion);select
random_column
from
table
start with parent_id = 'parent_node_id'
connect by prior child_up_id = parent_id
注意这个查询中没有 where 子句。但是,start with ... connect by 仍然可以与 where clause 一起使用。您可以在此处详细了解这些关键字的工作原理。
我不知道现有的 NHibernate 语法是否允许这样做,但是对于分层查询有一个 ANSI 标准语法可能会证明是有用的。但是,我相信它仅适用于 11R2 及更高版本,因此我不确定它是否对您有用。有关详细信息,请参阅递归子查询重构。