通用的DAO和嵌套属性支持 [英] Generic DAO and nested properties support

查看:116
本文介绍了通用的DAO和嵌套属性支持的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图通过DAO对象执行数据库访问,并且遇到了需要查询另一个实体中的字段的情况。



考虑到两个通过外键 EntityA.idEntityB 连接到实体A的实体(EntityA和EntityB)。



I有 GenericDao< EntityA> daoA ,我试图获得匹配确定的EntityB字段的所有结果: idEntityB.fieldOfB 全部在相同的 find 的方法。



可能吗?如果是的话,一些方向会很好。谢谢

编辑



我的代码示例:



实体



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

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



DAO Access < h3>

  GenericDao< EntityA> daoA = // ... 

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

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

错误信息类似于无法解析属性idEntityB.fieldOfB



edit 2



我能找到像我想要的东西去做。虽然我的API稍有不同,但我相信这对任何在自己的项目早期阶段遇到此问题的人来说都是很有帮助的。

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


该框架具有强大而灵活的搜索功能。
通过将搜索对象传递给一般
和泛型DAO上的搜索方法来使用它。


这个项目完全支持嵌套属性。

解决方案

这是我的通用Criteria过滤方法。

根据bean约定的属性具有以下格式 foo.bar.name

使用Criteria API可以从可以添加给定的过滤映射和限制。我在测试过程中观察到的一个特例是,对标识符属性的过滤不需要新的子标准,因为此属性已被获取。

  / ** 
*根据给定的Type和给定的过滤器映射创建一个分离的条件。
*
* @param类型Criteria的目标类型。
* @param identifierPropertyName如果提供(不为空),则可以为给定类型标识标识符
*属性名称,以简化
*查询,如果标识符属性是唯一属性
*在父级上使用,不需要子查询。
* @param过滤器
*
* @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);

//使用树添加限制
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());

退货标准;
}

/ **
*使用虚拟根节点TreeNode从给定Set创建一棵树。
*
* @param< T>
*
* @param过滤器
* @param identifierPropertyName与其
*父属性合并的属性名称。例如:< b> user.id< / b>被视为单个
*属性。
* @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();

/ *
*为实体属性创建关键属性树
* /
final TreeNode< Entry< String,Object>> rootNode = new TreeNode< Entry< String,Object>>(
new SimpleEntry< String,Object>(root,null)); (it.hasNext())
{
final Entry< String,Object>

entry = it.next();
// foo.bar.name
final String key = entry.getKey();

String []道具;
$ b $ * b $ b *检查我们是否有嵌套层次结构
* /
if(key.contains(。))
{
props = key.split(\\\。);
//检查标识符,因为标识符属性名称不是
//需要新的子标准
if(!StringUtils.isBlank(identifierPropertyName))
{
int propsTempLength = props.length - 1;
if(props [propsTempLength] .equals(identifierPropertyName))
{
props = Arrays.copyOf(props,propsTempLength);
propsTempLength--;
道具[propsTempLength] =道具[propsTempLength] +。 + identifierPropertyName;
}
}

//检查开始的this标识符,该标识符需要为
//由于hibernate没有识别出$ b $ //为投影添加
if(props.length> 1&& props [0] .equals(this))
{
props [0] =this。 +道具[1];

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

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

//创建嵌套标准
for(int i = 0; i< props.length; i ++)
{
Object valueAdd;

//只有叶需要值
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));

//尝试获得真实节点
TreeNode< Entry< String,Object>> childNode = currNode.getChild(childTempNode.getElement());
//检查我们是否已经有一个唯一的节点
if(childNode == null)
{
childNode = childTempNode;
//如果新节点是新节点,则添加新的子节点
currNode.addChild(childNode);
}

currNode = childNode;
}
}

return rootNode;
}

/ **
*递归地将给定TreeNode中包含的给定限制条件添加到
*条件中。
*
* @param criteria
* @param treeNode
* /
public static void addRestrictions(final DetachedCriteria criteria,
final TreeNode< Entry< String ,Criterion>> treeNode)
{
//如果我们有一个叶子,只需添加限制
if(treeNode.getChildren()。size()== 0)
criteria 。新增(treeNode.getElement()的getValue());
else
{
//创建新的子标准并迭代子元素
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());


$ b $ * b $ b *工具类
* /

/ **
* Generic使用Set的TreeNode实现来保持其子节点只允许
*独特的子节点。
* /
public class TreeNode< T>
{
private final T元素;

private final Set< TreeNode< T>>儿童;

公共TreeNode(final T元素)
{
if(element == null)
throw new IllegalArgumentException(元素不能为空);

this.element = element;

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

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

/ **
*检索等于给定孩子的孩子。
*
* @param children
* @return如果没有孩子等于给定的返回null。
* /
public TreeNode< T> getChildren(最终TreeNode< T>子>
<
final迭代器< TreeNode< T>> it = this.childrens.iterator();

TreeNode< T> next = null; (it.hasNext())
{
next = it.next();


if(next.equals(children))
next next;
}

返回null;
}

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

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

/ **
*检查此实例的元素是否等于给定
*对象中的元素。
* /
@Override
public boolean equals(final Object obj)
{
if(this == obj)
return true;

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

返回this.element.equals(treeNode.element);
}
else
返回false;
}

@Override
public int hashCode()
{
int hash = 1;
hash = hash * 17 + this.element.hashCode();
返回散列;
}
}

希望这对你有所帮助。或者看看你提到的通用dao项目。我知道这个项目,并检查出来,但从未下载过。



使用这种方法,可以创建一个非常简单的查询,如下所示:

 地图< 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));

列表< Class> data = HibernateUtils.createDetachedCriteria(Class,从sessionFactory获取标识符,过滤器).getExecutableCriteria(session).list();

这种将属性名称作为关键字添加到限制中的奇怪方法与限制对属性名称没有getter和setter。



自定义过滤
$ b

我的真实应用程序使用类似的代码,它不仅限于 Criterion 类。
对于我的web层,我创建了自定义过滤器,它等同于限制api,但客户端不再需要hibernate jar。
$ b

编辑



跨非实体(如组件和组合) ID不支持。它可以很容易地在 ClassMetadata 的帮助下进行扩展,无需反射即可支持它们。如果需要代码,我可以提供。


I am trying to perform a DB access through a DAO object, and I have bumped into the case where I need to query a field in another Entity.

Considering two entities (EntityA and EntityB) that are connected in entity A through the foreign key EntityA.idEntityB.

I have GenericDao<EntityA> daoA and I am trying to get all the results that match a determined field of EntityB: idEntityB.fieldOfB all in the same find method of the dao.

Is it possible? And if so some directions would be nice. Thanks

edit

An example of my code:

Entities

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);

The error message is something like "Could not resolve property idEntityB.fieldOfB"

edit 2

I was able to find something like what I want to do. Although my API is slightly different I believe this is helful for anyone who gets across this problem at an early stage of their own project.

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

The framework features a powerful and flexible search functionality. This is used by passing a search object to search methods on general and generic DAOs.

Searches with nested properties are fully supported in this project.

解决方案

Here is my generic Criteria filtering method.

Properties according to bean conventions have following form foo.bar.name.
With Criteria API a tree can be build from a given filtering map and Restrictions can be added. One special case I observed during testing is that filtering on the identifier property does not needs a new subcriteria since this property is already fetched.

/**
 * 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;
    }
}

Hope this helps you. Or have a look at the generic dao project you mentioned. I knew about this project and checked it out but never downloaded it.

Using this approach a query can be created very simple like following:

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

This odd approach to add the property name as the key and into the Restrictions is related to the fact that Restrictions have no getter and setter for property names.

Custom filtering

My real application uses similar code which is not restricted to Criterion class only. For my web tier I created custom filters which are equivalent to Restrictions api but the client does not needs hibernate jar's anymore.

Edit

Generic filtering across non-entities such as component's and composite-id's is not supported. It can easily be extended with help of ClassMetadata to support them without need for reflection. If code is needed i can provide it.

这篇关于通用的DAO和嵌套属性支持的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆