Могу ли я создать собственное выражение, не используя предложение where? - PullRequest
3 голосов
/ 19 августа 2010

Хотя я уже решил эту проблему в предыдущем вопросе, используя собственный запрос. Теперь мне интересно, возможно ли создать собственное выражение, которое можно использовать в критериях без использования оператора where? Причина, по которой я не хочу использовать предложение 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);

У меня есть ощущение, что это связано с .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. Который является недопустимым запросом, потому что это предложение не относится к where.

Это запрос, который я ожидал бы сгенерировать 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. Вы можете узнать больше о том, как работают эти ключевые слова здесь .

1 Ответ

0 голосов
/ 20 октября 2010

Я не знаю, допускает ли это существующий синтаксис NHibernate, но существует стандартный синтаксис ANSI для иерархических запросов, который может оказаться полезным. Я считаю, что он работает только в 11R2 и выше, поэтому я не уверен, что это полезно для вас. См. Рекурсивный рефакторинг подзапросов для получения дополнительной информации.

...