java - 能够对域代码的每个实体执行选择的通用方法

标签 java hibernate generics

我想要一个通用方法来执行 SELECT * FROM entity<T> WHERE entity<T>.primaryKey = method_parameter我可以在域代码的每个实体上使用它。

到目前为止,我有这个非通用方法。它返回一个列表,该列表始终只有一个元素,因为主键是唯一的:

public static List<App> selectOneApp(int appid) {
    Session session = HibernateSessionFactory.getFactory().openSession();
    List<App> list = null;
    Transaction tx = null;

    try {
        tx = session.beginTransaction();

        CriteriaBuilder builder = session.getCriteriaBuilder();
        CriteriaQuery<App> criteria = builder.createQuery(App.class);
        Root<App> root = criteria.from(App.class);
        criteria.select(root);

        criteria.where(builder.equal(root.get(App_.appId), appid));
        //equivalent to WHERE App.appid = appid

        list = session.createQuery(criteria).getResultList();

        tx.commit();
    } catch (HibernateException e) {
        if (tx != null)
            tx.rollback();
        log.error(e);
    } finally {
        session.close();
    }
    return list;
}

我希望它是这样的:

public static <T> List<T> selectOneRow(int key, Class<T> clazz) {
    Session session = HibernateSessionFactory.getFactory().openSession();
    List<T> list = null;
    Transaction tx = null;

    try {
        tx = session.beginTransaction();

        CriteriaBuilder builder = session.getCriteriaBuilder();
        CriteriaQuery<T> criteria = builder.createQuery(clazz);
        Root<T> root = criteria.from(clazz);
        criteria.select(root);

        criteria.where(builder.equal(root.get(clazz_.Id), key)); 
        // I got stuck here. How can I pass a generic key?

        list = session.createQuery(criteria).getResultList();

        tx.commit();
        ...
    return list;
}

我使用hibernate的代码生成器自动生成域代码。由此我生成了 JPA 元模型,一切都很好且类型安全。

我想我必须生成某种继承结构,其中父类只有一个 get() 方法和一个主键。所有想要使用此通用选择方法的实体类都从该父类继承。但我不确定如何做到这一点,或者是否可能。

这个问题是我的引用,但缺少标准。其中部分:Java class - how to pass Generic Object to a function

我的数据模型的片段:

CREATE TABLE app_type(
    appTypeID TINYINT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
    app_type_name VARCHAR(32)
);

CREATE TABLE app(
    appID INT UNSIGNED NOT NULL PRIMARY KEY,
    app_name VARCHAR(191),
    appTypeID TINYINT UNSIGNED,
    pubID INT UNSIGNED,
    CONSTRAINT fk_app_appType_appTypeID
        FOREIGN KEY (appTypeID) 
        REFERENCES app_type(appTypeID) 
        ON UPDATE CASCADE);

CREATE TABLE publisher(
    pubID INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
    publisher_name VARCHAR(191));

CREATE TABLE ref_app_publisher(
    appID INT UNSIGNED NOT NULL,
    pubID INT UNSIGNED NOT NULL,
    PRIMARY KEY(appID, pubID),
    UNIQUE INDEX ux_refAppPublisher_pubID_appID (pubID, appID),
    CONSTRAINT fk_refAppPublisher_app_appID
        FOREIGN KEY (appID) 
        REFERENCES app(appID) 
        ON UPDATE CASCADE,
    CONSTRAINT fk_refAppPublisher_publisher_pubID 
        FOREIGN KEY (pubID) 
        REFERENCES publisher(pubID)
        ON UPDATE CASCADE);

谢谢!

最佳答案

我成功了!

调用者将始终知道该操作应该作用于哪个类或实体。因此,诀窍是通过添加参数 ormClasssingularAttribute 来赋予调用者更多责任。

/**
 * Select a single row from any ORM type. Returns a single result in a list
 * or an empty list. Avoids NoResultException() from JPA's getSingleResult()
 * method
 * 
 * @param key
 *            The unique primary key to select.
 * @param ormClass
 *            The ORM class to select.
 * @param singularAttribute
 *            A JPA SingularAttribute<<ormType>, <primaryKey> data
 *            type> containing the mapping to the primary key.
 * @return list The selected ORM type in a list. If no result the list is
 *         empty.
 */
public static <T, X> List<T> selectOneRow(int key, Class<T> ormClass,
        SingularAttribute<T, X> singularAttribute) {
    Session session = HibernateSessionFactory.getFactory().openSession();
    List<T> list = null;
    Transaction tx = null;

    try {
        tx = session.beginTransaction();

        CriteriaBuilder builder = session.getCriteriaBuilder();
        CriteriaQuery<T> criteria = builder.createQuery(ormClass);
        Root<T> root = criteria.from(ormClass);
        criteria.select(root);
        criteria.where(builder.equal(root.get(singularAttribute), key));

        list = session.createQuery(criteria).getResultList();

        tx.commit();
    } catch (HibernateException e) {
        if (tx != null)
            tx.rollback();
        log.error(e);
    } finally {
        session.close();
    }
    return list;
}

注意:在将 SingularAttribute 作为参数传递时,我遇到了无法解释的 NullPointerException,这花了我一些时间才弄清楚。解决方案如下:Hibernate/JPA - NullPointerException when accessing SingularAttribute parameter

关于java - 能够对域代码的每个实体执行选择的通用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41579417/

相关文章:

java - 嵌入 hsql 的一些有趣的事情

java - 日期未正确插入数据库

java - 尝试实现 JWT 安全性时,Hibernate 出现 StackOverflowError

java - 我们可以在运行时从泛型类型实例化一个对象吗?

java - Java 中的语法 <T extends Class<T>>

java - @MockBeans 有类似 Lombok @AllArgConstructor 的东西吗?

java - GAE blobstore 在何处以及如何存储文件(或 blob)?

java - NoClassDefFoundError,在我的主 jar 中使用它之前加载我创建的库时遇到问题

java - RMI 和 JMX 套接字工厂

c# - 从泛型类继承时需要 T 的列表或枚举器的建议