Хотя я уже решил эту проблему в предыдущем вопросе, используя собственный запрос. Теперь мне интересно, можно ли создать пользовательское выражение, которое можно использовать в критериях, без использования предложения where? Причина, по которой я не хочу использовать предложение where, заключается в том, что Oracle connect by ... start with ...
(здесь а>) заявление. Я следовал этому страницу, чтобы начать. Однако это сгенерирует такой код, как 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);
У меня есть ощущение, что это связано с .Add()
из DetachedCriteria, но не уверен на 100%. К сожалению, я не могу найти много документации о создании пользовательского выражения.
Редактировать: теперь, когда я думаю об этом, похоже, что я лаю не на то дерево. Пока это не критично (у меня уже есть достойная реализация). Мне все еще интересно посмотреть, как я могу дополнительно настроить NHibernate.
Редактировать 2: поскольку NHibernate не поддерживает проприетарную функцию Oracle, start with ... connect by
. Я пытаюсь узнать больше о расширении NHibernate, добавив для него встроенную поддержку. Я знаю, что могу зарегистрировать эти функции на собственном диалекте. Но мне интересно, можно ли реализовать его как критерий, чтобы я мог использовать его с другими запросами критериев. Код, который я разместил, отлично работает и правильно создает действительный SQL, но когда я добавляю StartWithConnectByCriteria в свои критерии, NHibernate выдает запрос, например select this_.id from table where start with ... connect by
. Это недопустимый запрос, потому что это предложение не относится к тому, где.
Это запрос, который я ожидаю от NHibernate.
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
. Подробнее о том, как работают эти ключевые слова, можно прочитать здесь.