通用DAO和嵌套属性支持

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

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

我有GenericDao 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 daoA = // ... Set filter = new HashSet(); filter.add(Restrictions.eq("idEntityB.fieldOfB")); List list = dao.findByFilter(filter); 

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

编辑2

我能够找到类似我想做的事情。 尽管我的API略有不同,但我相信这对于在自己项目的早期阶段遇到这个问题的人来说是有帮助的。

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

该框架具有强大而灵活的搜索function。 通过将搜索对象传递给常规和通用DA​​O上的搜索方法来使用此方法。

此项目完全支持使用嵌套属性的搜索。

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

根据bean约定的属性具有以下formsfoo.bar.name
使用Criteria API,可以从给定的过滤映射构建树,并可以添加限制。 我在测试期间观察到的一个特例是,对identifier属性的过滤不需要新的子标准,因为已经获取了此属性。

 /** * 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 filters) { final DetachedCriteria criteria = DetachedCriteria.forClass(type); // add restrictions using tree final TreeNode> rootNode = HibernateUtils2.createTree(filters.entrySet(), identifierPropertyName); final Iterator>> 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  * * @param filters * @param identifierPropertyName Property name which is merged with its * parent property. Example: user.id is treated as single * property. * @return */ public static  TreeNode> createTree(final Set> filters, final String identifierPropertyName) { final Iterator> it = filters.iterator(); /* * create key property tree for Entity properties */ final TreeNode> rootNode = new TreeNode>( new SimpleEntry("root", null)); while (it.hasNext()) { final Entry 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> 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> childTempNode = new TreeNode>( new SimpleEntry(props[i], valueAdd)); // try to get the real node TreeNode> 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> 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>> 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 { private final T element; private final Set> childrens; public TreeNode(final T element) { if (element == null) throw new IllegalArgumentException("Element cannot be null"); this.element = element; this.childrens = new HashSet>(); } public void addChildren(final TreeNode 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 getChildren(final TreeNode children) { final Iterator> it = this.childrens.iterator(); TreeNode next = null; while (it.hasNext()) { next = it.next(); if (next.equals(children)) return next; } return null; } public T getElement() { return this.element; } public Set> 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 filters = new HashMap(); filters.put("foo.bar.name", Restrictions.like("name", "peter")); filters.put("foo.test.id", Restrictions.eq("id", 2)); List data = HibernateUtils.createDetachedCriteria(Class, "get identifier from sessionFactory", filters).getExecutableCriteria(session).list(); 

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

自定义过滤

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

编辑

不支持跨组件和复合ID等非实体的通用过滤。 它可以通过ClassMetadata轻松扩展,以支持它们而无需reflection。 如果需要代码,我可以提供。

看看这个例子: 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层的工作。