Java JPA:通过接口而不是实现查找

Java JPA:通过接口而不是实现查找,java,hibernate,jpa,playframework,annotations,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.create

我希望将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) atplay.db.jpa.DefaultJPAApi.lambda$和事务$3(DefaultJPAApi.java:197)

我的疑问是,如果我使用的查询语句与接口配合良好,为什么会出现这个问题

这项工作:

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

    }
@覆盖
公共集合getAllGoods(){
返回此.jpaApi.withTransaction(()->{
收款货物=空;
试一试{
EntityManager em=this.jpaApi.em();
Query Query=em.createQuery(“从货物g中选择g”,货物.class);
货物=query.getResultList();
}捕获(例外e){
//TODO:处理异常
e、 printStackTrace();
}
退货;
});
}

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

<T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass)
没有得到编译器警告。
resultClass
参数是当然不会告诉
entityManager
您要查询的实体类型。这是通过查询的
select g from Goods g
部分完成的,顺便提一下,
Goods
是实体
goodsiml
的别名(您可以使用
@entity(name=“Bads”)注释
goodsiml
实体
从Bads b中选择b
也可以工作)

现在,如果我理解正确,您会问为什么调用
em.find(entityClass,primaryKey)
失败,而
Goods.class
用于
entityClass
。您可以在javadoc中找到
EntityManager
的答案,其中
find
被称为抛出:

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

毫不奇怪,实体类型是一个用
@entity
注释的类


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

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

<T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass)
没有得到编译器警告。
resultClass
参数是当然不会告诉
entityManager
您要查询的实体类型。这是通过查询的
select g from Goods g
部分完成的,顺便提一下,
Goods
是实体
goodsiml
的别名(您可以使用
@entity(name=“Bads”)注释
goodsiml
实体
从Bads b中选择b
也可以工作)

现在,如果我理解正确,您会问为什么调用
em.find(entityClass,primaryKey)
失败,而
Goods.class
用于
entityClass
。您可以在javadoc中找到
EntityManager
的答案,其中
find
被称为抛出:

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

毫不奇怪,实体类型是一个用
@entity
注释的类


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

JPA API不认为接口值得持久化处理。数据核JPA确实允许JPQL,但不知道任何其他的,并且你在那里进入供应商扩展,所以,我只能使用JPQL中的接口,但不在.find方法中。正如我所说的,JPA不考虑接口,所以如果遵守规范,就不能使用它们,只有我知道的1个供应商支持它们。但是你没有使用它。为什么接口在getAllGoods()中工作?在你的例子中,你没有使用接口,你已经将实体名黑客化为接口类的名称。这就是JPQL所使用的,并将其解释为GoodsImp。因此,问题的标题是非此即彼。JPA API不认为接口值得持久化处理。数据核JPA确实允许JPQL,但不知道任何其他的,并且你在那里进入供应商扩展,所以,我只能使用JPQL中的接口,但不在.find方法中。正如我所说的,JPA不考虑接口,所以如果遵守规范,就不能使用它们,只有我知道的1个供应商支持它们。但是你没有使用它。为什么接口在getAllGoods()中工作?在你的例子中,你没有使用接口,你已经将实体名黑客化为接口类的名称。这就是JPQL所使用的,并将其解释为GoodsImp。所以问题的标题是毫无意义的伟大的答案,这就是我想要的。谢谢。因此,我的选项是,使用带别名的TypedQuery或使用实体本身的find方法。非常感谢。回答得很好,这就是我想要的。谢谢。因此,我的选项是,使用带别名的TypedQuery或使用实体本身的find方法。谢谢。