通用DAO和嵌套属性的支持(Generic DAO and nested properties su

2019-09-21 07:12发布

我试图执行通过DAO对象数据库访问,我也碰到了,我需要查询的另一个实体的现场情况。

考虑到两个实体(EntityA和EntityB),可通过外键连接实体A 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 Access

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略有不同,我相信这是helful的人谁在自己的项目的早期阶段过这个问题得到。

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

该框架拥有一个强大而灵活的搜索功能。 这是通过搜索对象要搜索的一般和通用的DAO方法使用。

与嵌套属性搜索在这个项目中得到充分支持。

Answer 1:

这里是我的通用标准过滤方法。

根据豆约定属性有如下形式foo.bar.name
与标准API树可以从一个给定的过滤映射来建立并且可以添加限制。 我在测试过程中发现的一个特殊情况是,因为这个属性已经获取的标识属性过滤并不需要一个新的子标准。

/**
 * 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();

这个奇怪的方法来添加属性名称作为键,进入限制是相关的事实,限制对属性名称不getter和setter。

自定义筛选

我真正的应用程序使用不局限于类似的代码Criterion唯一的类。 对于我的web层我创建了相当于限制API,但客户并不需要冬眠罐子的再定义过滤器。

编辑

不支持跨非实体,如组件和复合-ID的通用过滤。 它可以很容易地帮助扩展ClassMetadata支持他们,而不需要进行反思。 如果需要的代码,我可以提供。



Answer 2:

看看这个例子: 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

这点ORM是Hibernate提供:您不需要用钥匙工作,你有对象。 转换该表示与钥匙的关系映射是Hibernate的ORM层的工作。



文章来源: Generic DAO and nested properties support