简体   繁体   English

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

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

So, After a 10+ year break I'm coming back to Java and trying out stuff with JPA and Java generics.所以,在 10 多年的休息之后,我又回到 Java 并尝试使用 JPA 和 Java 泛型的东西。 I've created a generics based findAll(other) JPA query that basically does我创建了一个基于泛型的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 ManagedType was 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.这是抽象的 DAO 类。 I extend this for the implementation classes as I need to be more specific doing other activities - mostly making sure lazy sets are loaded.我将其扩展到实现类,因为我需要更具体地执行其他活动 - 主要是确保加载惰性集。

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.如果有的话,我希望它在那里,以便其他人可以使用它。

Hat tip to Adam Bien if you don't want to use createQuery with a String and want type safety:如果您不想将createQueryString一起使用并希望类型安全,请向 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(); }

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

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

您还可以对所有实体使用名为 findAll 的 namedQuery 并在通用 FindAll 中调用它

entityManager.createNamedQuery(persistentClass.getSimpleName()+"findAll").getResultList();

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM