将 Java 泛型用于带有 WHERE 子句的 JPA findAll() 查询

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24572092/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 13:06:15  来源:igfitidea点击:

Using Java generics for JPA findAll() query with WHERE clause

javagenericsjpacriteria-api

提问by jim.richards

So, After a 10+ year break I'm coming back to Java and trying out stuff with JPA and Java generics. I've created a generics based findAll(other)JPA query that basically does

所以,在 10 多年的休息之后,我又回到 Java 并尝试使用 JPA 和 Java 泛型的东西。我创建了一个基于泛型的findAll(other)JPA 查询,它基本上可以

SELECT * FROM source WHERE other_id = other.id;

This is where I'm up to. It works, but I'm wondering if there's a better, cleaner way to do it. Using ManagedTypewas hard, and there's not much complete documentation or simple examples around.

这就是我要做的。它有效,但我想知道是否有更好,更清洁的方法来做到这一点。使用起来ManagedType很困难,并且没有太多完整的文档或简单的示例。

I've decided to keep my code as generic as possible (no pun intended) so I use JPA2.

我决定让我的代码尽可能通用(没有双关语)所以我使用 JPA2。

This is the root of all Entity Classes. I probably don't need it, but it stops me from having basic mistakes.

这是所有实体类的根。我可能不需要它,但它阻止我犯基本错误。

import java.io.Serializable;

public abstract class DomainObject implements Serializable {

    private static final long serialVersionUID = 1L;

    public abstract void setId(Long id);
    public abstract Long getId();

}

This is the abstract DAO class. I extend this for the implementation classes as I need to be more specific doing other activities - mostly making sure lazy sets are loaded.

这是抽象的 DAO 类。我将其扩展到实现类,因为我需要更具体地执行其他活动 - 主要是确保加载惰性集。

public abstract class GenericDAOImpl<T extends DomainObject, T2 extends DomainObject> implements GenericDAO<T, T2> {

private Class<T> type;

@PersistenceContext
protected EntityManager entityManager;

public GenericDAOImpl(Class<T> type) {
    super();
    this.type = type;
}

... save and delete classes go here

@Override
public List<T> findAll(T2 where) {

    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery<T> criteriaQuery = criteriaBuilder.createQuery(type);
    Root<T> rootQuery = criteriaQuery.from(type);
    if (where != null) {

        EntityType<T> entity = entityManager.getMetamodel().entity(type);

        SingularAttribute<? super T, ?> attribute = null;
        for (SingularAttribute<? super T, ?> singleAttribute: entity.getSingularAttributes()) {
            // loop through all attributes that match this class
            if (singleAttribute.getJavaType().equals(where.getClass())) {
                // winner!
                attribute = singleAttribute;
                break;
            }
        }
        // where t.object = object.getID()
        criteriaQuery.where(criteriaBuilder.equal(rootQuery.get(attribute), where));
    }
    criteriaQuery.select(rootQuery);
    TypedQuery<T> query = entityManager.createQuery(criteriaQuery);

    // need this to make sure we have a clean list?
    // entityManager.clear();
    return query.getResultList();
}

Any suggestions? If anything, I want this out there so other people can make use of it.

有什么建议?如果有的话,我希望它在那里,以便其他人可以使用它。

回答by Eduard

This will work, and if you need where statement you can add it as parameter.

这将起作用,如果您需要 where 语句,您可以将其添加为参数。

class GenericDAOWithJPA<T, ID extends Serializable> {

.......

......

public List<T> findAll() {
            return entityManager.createQuery("Select t from " + persistentClass.getSimpleName() + " t").getResultList();
    }
}

回答by R. Gulbrandsen

I found this page very useful

我发现这个页面非常有用

https://code.google.com/p/spring-finance-manager/source/browse/trunk/src/main/java/net/stsmedia/financemanager/dao/GenericDAOWithJPA.java?r=2

https://code.google.com/p/spring-finance-manager/source/browse/trunk/src/main/java/net/stsmedia/financemanager/dao/GenericDAOWithJPA.java?r=2

public abstract class GenericDAOWithJPA<T, ID extends Serializable> {

    private Class<T> persistentClass;

    //This you might want to get injected by the container
    protected EntityManager entityManager;

    @SuppressWarnings("unchecked")
    public GenericDAOWithJPA() {
            this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    @SuppressWarnings("unchecked")
    public List<T> findAll() {
            return entityManager.createQuery("Select t from " + persistentClass.getSimpleName() + " t").getResultList();
    }
}

回答by Adam

Hat tip to Adam Bien if you don't want to use createQuerywith a Stringand want type safety:

如果您不想使用createQueryaString并且想要类型安全,请给 Adam Bien 提示:

 @PersistenceContext
 EntityManager em;

 public List<ConfigurationEntry> allEntries() {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<ConfigurationEntry> cq = cb.createQuery(ConfigurationEntry.class);
        Root<ConfigurationEntry> rootEntry = cq.from(ConfigurationEntry.class);
        CriteriaQuery<ConfigurationEntry> all = cq.select(rootEntry);
        TypedQuery<ConfigurationEntry> allQuery = em.createQuery(all);
        return allQuery.getResultList();
 }
 @PersistenceContext
 EntityManager em;

 public List<ConfigurationEntry> allEntries() {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<ConfigurationEntry> cq = cb.createQuery(ConfigurationEntry.class);
        Root<ConfigurationEntry> rootEntry = cq.from(ConfigurationEntry.class);
        CriteriaQuery<ConfigurationEntry> all = cq.select(rootEntry);
        TypedQuery<ConfigurationEntry> allQuery = em.createQuery(all);
        return allQuery.getResultList();
 }

http://www.adam-bien.com/roller/abien/entry/selecting_all_jpa_entities_as

http://www.adam-bien.com/roller/abien/entry/selecting_all_jpa_entities_as

回答by vvs

you can also use a namedQuery named findAll for all your entities and call it in your generic FindAll with entityManager.createNamedQuery(persistentClass.getSimpleName()+"findAll").getResultList(); }`

您还可以对所有实体使用名为 findAll 的 namedQuery 并在通用 FindAll 中使用entityManager.createNamedQuery(persistentClass.getSimpleName()+"findAll").getResultList(); }`