1

DAOオブジェクトを介してDBアクセスを実行しようとしていますが、別のエンティティのフィールドをクエリする必要がある場合に遭遇しました。

外部キーを介してエンティティAで接続されている2つのエンティティ(EntityAとEntityB)について考えますEntityA.idEntityB

私は持っていてGenericDao<EntityA> daoA、EntityBの決定されたフィールドに一致するすべての結果を取得しようとしています:idEntityB.fieldOfBすべてdaoの同じfindメソッドで。

出来ますか?もしそうなら、いくつかの方向性がいいでしょう。ありがとう

編集

私のコードの例:

エンティティ

public class EntityA {
    @JoinColumn(name = "id_entity_b", referencedColumnName = "id")
    @ManyToOne(optional = false, fetch = FetchType.EAGER)
    private EntityB idEntityB;
    // getter+setter...
}

public class EntityB {
    // ...
    private String fieldOfB;
    // getter+setter...
}

DAOアクセス

GenericDao<EntityA> daoA = // ...

Set<Criterion> filter = new HashSet<Criterion>();
filter.add(Restrictions.eq("idEntityB.fieldOfB"));

List<EntityA> list = dao.findByFilter(filter);

エラーメッセージは、「プロパティidEntityB.fieldOfBを解決できませんでした」のようなものです

編集2

自分がやりたいことのようなものを見つけることができました。私のAPIは少し異なりますが、自分のプロジェクトの初期段階でこの問題に遭遇した人にとっては、これは非常に有益だと思います。

http://code.google.com/p/hibernate-generic-dao/

フレームワークは、強力で柔軟な検索機能を備えています。これは、検索オブジェクトを一般および汎用DAOの検索メソッドに渡すことによって使用されます。

このプロジェクトでは、ネストされたプロパティを使用した検索が完全にサポートされています。

4

2 に答える 2

3

これが私の一般的なCriteriaフィルタリング方法です。

Beanの規則に従ったプロパティは、次の形式になりfoo.bar.nameます。
Criteria APIを使用すると、特定のフィルタリングマップからツリーを構築し、制限を追加できます。テスト中に私が観察した特別なケースの1つは、識別子プロパティのフィルタリングでは、このプロパティが既にフェッチされているため、新しいサブ基準は必要ないということです。

/**
 * Creates a detached criteria from the given Type and given map of filters.
 * 
 * @param type Target type the Criteria is build for.
 * @param identifierPropertyName If provided (not null) the identifier
 *            property name can be identified for the given type to simplify
 *            the queries if the identifier property is the only property
 *            used on the parent no subqueries are needed.
 * @param filters
 * 
 * @see #createTree(Set, String)
 * @see #addRestrictions(DetachedCriteria, TreeNode)
 * 
 * @return
 */
public static DetachedCriteria createDetachedCriteria(final Class<?> type, final String identifierPropertyName,
    final Map<String, Criterion> filters)
{
    final DetachedCriteria criteria = DetachedCriteria.forClass(type);

    // add restrictions using tree
    final TreeNode<Entry<String, Criterion>> rootNode = HibernateUtils2.createTree(filters.entrySet(),
        identifierPropertyName);

    final Iterator<TreeNode<Entry<String, Criterion>>> it = rootNode.getChildren().iterator();

    while (it.hasNext())
        HibernateUtils.addRestrictions(criteria, it.next());

    return criteria;
}

/**
 * Creates a Tree from the given Set using a fictional root TreeNode.
 * 
 * @param <T>
 * 
 * @param filters
 * @param identifierPropertyName Property name which is merged with its
 *            parent property. Example: <b>user.id</b> is treated as single
 *            property.
 * @return
 */
public static <T extends Object> TreeNode<Entry<String, T>> createTree(final Set<Entry<String, T>> filters,
    final String identifierPropertyName)
{

    final Iterator<Entry<String, Object>> it = filters.iterator();

    /*
     * create key property tree for Entity properties
     */
    final TreeNode<Entry<String, Object>> rootNode = new TreeNode<Entry<String, Object>>(
        new SimpleEntry<String, Object>("root", null));

    while (it.hasNext())
    {
        final Entry<String, Object> entry = it.next();
        // foo.bar.name
        final String key = entry.getKey();

        String[] props;

        /*
         * check if we have a nested hierarchy
         */
        if (key.contains("."))
        {
            props = key.split("\\.");
            // check for identifier since identifier property name does not
            // need new subcriteria
            if (!StringUtils.isBlank(identifierPropertyName))
            {
                int propsTempLength = props.length - 1;
                if (props[propsTempLength].equals(identifierPropertyName))
                {
                    props = Arrays.copyOf(props, propsTempLength);
                    propsTempLength--;
                    props[propsTempLength] = props[propsTempLength] + "." + identifierPropertyName;
                }
            }

            // check for "this" identifier of beginning, which needs to be
            // added for projections because of hibernate not recognizing it
            if (props.length > 1 && props[0].equals("this"))
            {
                props[0] = "this." + props[1];

                props = ArrayUtils.remove(props, 1);
            }
        }
        else
            props = new String[]
            {
                key
            };

        TreeNode<Entry<String, Object>> currNode = rootNode;

        // create nested criteria
        for (int i = 0; i < props.length; i++)
        {
            Object valueAdd;

            // only leaf needs value
            if (i != props.length - 1)
                valueAdd = null;
            else
                valueAdd = entry.getValue();

            final TreeNode<Entry<String, Object>> childTempNode = new TreeNode<Entry<String, Object>>(
                new SimpleEntry<String, Object>(props[i], valueAdd));

            // try to get the real node
            TreeNode<Entry<String, Object>> childNode = currNode.getChild(childTempNode.getElement());
            // check if we already have a unique node
            if (childNode == null)
            {
                childNode = childTempNode;
                // add new child to set if its a new node
                currNode.addChild(childNode);
            }

            currNode = childNode;
        }
    }

    return rootNode;
}

/**
 * Recursively adds the given Restriction's wrapped in the given TreeNode to
 * the Criteria.
 * 
 * @param criteria
 * @param treeNode
 */
public static void addRestrictions(final DetachedCriteria criteria,
    final TreeNode<Entry<String, Criterion>> treeNode)
{
    // if we have a leaf simply add restriction
    if (treeNode.getChildren().size() == 0)
        criteria.add(treeNode.getElement().getValue());
    else
    {
        // create new sub Criteria and iterate children's
        final DetachedCriteria subCriteria = criteria.createCriteria(treeNode.getElement().getKey());

        final Iterator<TreeNode<Entry<String, Criterion>>> it = treeNode.getChildren().iterator();

        while (it.hasNext())
            HibernateUtils.addRestrictions(subCriteria, it.next());
    }
}

/*
 * Utility classes
 */

/**
 * Generic TreeNode implementation with a Set to hold its children to only allow
 * unique children's.
 */
public class TreeNode<T>
{
    private final T element;

    private final Set<TreeNode<T>> childrens;

    public TreeNode(final T element)
    {
        if (element == null)
            throw new IllegalArgumentException("Element cannot be null");

        this.element = element;

        this.childrens = new HashSet<TreeNode<T>>();
    }

    public void addChildren(final TreeNode<T> children)
    {
        this.childrens.add(children);
    }

    /**
     * Retrieves the children which equals the given one.
     * 
     * @param children
     * @return If no children equals the given one returns null.
     */
    public TreeNode<T> getChildren(final TreeNode<T> children)
    {
        final Iterator<TreeNode<T>> it = this.childrens.iterator();

        TreeNode<T> next = null;

        while (it.hasNext())
        {
            next = it.next();
            if (next.equals(children))
                return next;
        }

        return null;
    }

    public T getElement()
    {
        return this.element;
    }

    public Set<TreeNode<T>> getChildrens()
    {
        return this.childrens;
    }

    /**
     * Checks if the element of this instance equals the one of the given
     * Object.
     */
    @Override
    public boolean equals(final Object obj)
    {
        if (this == obj)
            return true;

        if (obj != null && obj instanceof TreeNode)
        {
            final TreeNode<?> treeNode = (TreeNode<?>) obj;

            return this.element.equals(treeNode.element);
        }
        else
            return false;
    }

    @Override
    public int hashCode()
    {
        int hash = 1;
        hash = hash * 17 + this.element.hashCode();
        return hash;
    }
}

これがお役に立てば幸いです。または、あなたが言及した一般的なdaoプロジェクトを見てください。私はこのプロジェクトについて知っていて、チェックアウトしましたが、ダウンロードしたことはありませんでした。

このアプローチを使用すると、クエリは次のように非常に簡単に作成できます。

Map<String, Object> filters = new HashMap<String, Object>();
filters.put("foo.bar.name", Restrictions.like("name", "peter"));
filters.put("foo.test.id", Restrictions.eq("id", 2));

List<Class> data = HibernateUtils.createDetachedCriteria(Class, "get identifier from sessionFactory", filters).getExecutableCriteria(session).list();

プロパティ名をキーとして制限に追加するこの奇妙なアプローチは、制限にはプロパティ名のゲッターとセッターがないという事実に関連しています。

カスタムフィルタリング

Criterion私の実際のアプリケーションは、クラスのみに制限されていない同様のコードを使用しています。私のWeb層では、Restrictions apiと同等のカスタムフィルターを作成しましたが、クライアントはHibernatejarを必要としなくなりました。

編集

コンポーネントやcomposite-idなどの非エンティティ間の一般的なフィルタリングはサポートされていません。ClassMetadata振り返る必要なしにそれらをサポートする助けを借りて簡単に拡張することができます。コードが必要な場合、私はそれを提供することができます。

于 2012-08-20T19:26:18.847 に答える
1

この例を見てください:http://viralpatel.net/blogs/hibernate-one-to-one-mapping-tutorial-using-annotation/

エンティティ間の関係を次のように宣言する必要があります

public class EntityA {
    @JoinColumn(name = "id_entity_b")
    @ManyToOne(optional = false, fetch = FetchType.EAGER)
    private EntityB idEntityB;
    // getter+setter... and the rest
}

Integer使用する代わりにEntityB

これがHibernateが提供するORMのポイントです。キーを操作する必要はなく、オブジェクトを操作します。この表現をキーを使用したリレーショナルマッピングに変換するのは、HibernateのORMレイヤーの作業です。

于 2012-08-17T11:48:42.483 に答える