3

前の質問でネイティブクエリを使用してこの問題をすでに解決しましたが。where句を使用せずにCriteriaで使用できるカスタム式を作成できるかどうか疑問に思っています。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);

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が生成することを期待するクエリです。

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。これらのキーワードがどのように機能するかについて詳しくは、こちらをご覧ください。

4

1 に答える 1

0

既存のNHibernate構文でこれが可能かどうかはわかりませんが、階層クエリ用のANSI標準構文があります。11R2以降でしか動作しないと思いますが、お役に立てるかどうかはわかりません。詳細については、再帰サブクエリリファクタリングを参照してください。

于 2010-10-20T02:48:04.890 に答える