JPA:按接口而不是实现查找

时间:2017-09-14 01:03:51

标签: java hibernate jpa playframework annotations

我想将find方法与接口一起使用,而不是与实现一起使用。

这就是我的代码:

public Goods findGoods(Long goodsId) {
    return this.jpaApi.withTransaction(()->{
        Goods goods = null;
        try{
            EntityManager em = this.jpaApi.em();
            Query query = em.createQuery("select g from Goods g where id=:id", Goods.class);
            query.setParameter("id", goodsId);
            goods = (Goods) query.getSingleResult();
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        return goods;
    });
}

我的实体:

@Entity(name = "Goods")
@Table(name = "GOODS")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class GoodsImp implements Goods,  Serializable {
..
}

我的界面:

@JsonTypeInfo(include = JsonTypeInfo.As.PROPERTY, property = "type", 
use = Id.NAME, defaultImpl = GoodsImp.class, visible = true)
@JsonSubTypes({ @Type(value = ProductImp.class, name = "product"),
                @Type(value = ServiceImp.class, name = "service") })
@ImplementedBy(GoodsImp.class)
public interface Goods {
..
}

错误:

  

java.lang.IllegalArgumentException:无法找到persister:interfaces.Goods           在org.hibernate.internal.SessionImpl.find(SessionImpl.java:3422)           在org.hibernate.internal.SessionImpl.find(SessionImpl.java:3365)           在repository.JPAGoodsRepository.lambda $ deleteGoods $ 2(JPAGoodsRepository.java:58)           at play.db.jpa.DefaultJPAApi.lambda $ withTransaction $ 3(DefaultJPAApi.java:197)

我怀疑这就是为什么我有这个问题,如果我使用Query语句时可以正常使用该接口。

这有效:

 @Override
    public Collection<Goods> getAllGoods() {
        return this.jpaApi.withTransaction(() -> {
            Collection<Goods> goods = null;
            try {
                EntityManager em = this.jpaApi.em();
                Query query = em.createQuery("Select g from Goods g", Goods.class);
                goods = query.getResultList();
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }
            return goods;
        });

    }

1 个答案:

答案 0 :(得分:2)

您使用的EntityManager方法createQuery声明为:

<T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass)

Class<T> resultClass参数的唯一原因是推断T的类型,以便您可以写:

List<Goods> listOfGoods = em.createQuery("select g from Goods g where id=:id", Goods.class).getResultList();

没有收到编译器警告。 resultClass参数肯定不是告诉entityManager您要查询的实体类型。这是由查询的select g from Goods g部分完成的,顺便提一下,Goods是实体GoodsImpl的别名(您可以使用{{1}注释GoodsImpl实体}和@Entity(name = "Bads")也可以)。

现在,如果我理解正确,那么当select b from Bads b用于em.find(entityClass, primaryKey)时,您就会问为什么通话Goods.class失败了。您可以在entityClass的javadoc中找到答案,其中EntityManager被称为:

  

IllegalArgumentException - 如果第一个参数不表示实体类型

实体类型是一个带有find注释的类,毫无疑问。

如果你问为什么这就是它的实现方式,那么答案就很简单了。接口可以由几个类实现。假设您有多个实现@Entity的实体类,每个实体类都有自己的表和自己的id。没有理由不在这些不同的实体之间重叠。 JPA应该如何知道您希望获得哪些实体?