JPA: TypedQuery не дает результатов для унаследованных типов

#inheritance #jpa #named-query

#наследование #jpa #именованный запрос

Вопрос:

У меня есть объект, который расширяет другой объект:

 @Entity
@DiscriminatorValue("PARKING")
@Table(name="parkingPois")
@NamedQueries({
    @NamedQuery(name="ParkingPoiDao.findAll", query="SELECT p FROM ParkingPoiDao p"), 
    @NamedQuery(name="ParkingPoiDao.findById", query="SELECT p FROM ParkingPoiDao p WHERE p.parkingPoiId = :parkingPoiId")
})
public class ParkingPoiDao extends PoiDao implements Serializable {
    //@Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id")
    private int id;
    @Column(name="parkingPoiId")
    private String parkingPoiId;
    @Column(name="poiId")
    ...
}

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="poiType", discriminatorType=DiscriminatorType.STRING)
@Table(name="pois")
public abstract class PoiDao implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="poiId")
    private int poiId;
...
 

Когда я пытаюсь запросить parkingPoi, я не получаю никаких результатов.

         TypedQuery<ParkingPoiDao> query =
                em.createNamedQuery("ParkingPoiDao.findAll", ParkingPoiDao.class);
//      TypedQuery<ParkingPoiDao> query =
//              em.createNamedQuery("ParkingPoiDao.findById", ParkingPoiDao.class)
//              .setParameter("parkingPoiId", facilityId);
//              .setParameter("poiType", "ParkingPOI");
//      ParkingPoiDao pPoiDao = query.getSingleResult();
        List<ParkingPoiDao> pPoiDaos = query.getResultList();
 

(Как активные, так и удаленные запросы не дают результатов.)

В базе данных у меня есть таблица poi для родительского класса и «подтаблица» для parkingPois, которая содержит внешний ключ (pois.poiId).

В чем может быть причина??

Комментарии:

1. Вы пробовали выполнить сгенерированный запрос в базе данных, чтобы узнать, есть ли у какого-либо запроса какие-либо результаты?

Ответ №1:

Мне пришлось добавить parkingPoiId свойство к вашей ParkingPoiDao сущности, чтобы ParkingPoiDao.findById именованный запрос был действительным:

 @Entity
@Table(name="parkingPois")
@NamedQueries({
        @NamedQuery(name="ParkingPoiDao.findAll", query="SELECT p FROM ParkingPoiDao p"),
        @NamedQuery(name="ParkingPoiDao.findById", query="SELECT p FROM ParkingPoiDao p WHERE p.parkingPoiId = :parkingPoiId")
})
public class ParkingPoiDao extends PoiDao {

    private String parkingPoiId;

    public String getParkingPoiId() {
        return parkingPoiId;
    }

    public void setParkingPoiId(final String parkingPoiId) {
        this.parkingPoiId = parkingPoiId;
    }
}
 

Итак, с учетом этого следующий тест проходит с использованием обоих ваших запросов:

 @Test
@Transactional
public void return_parking_pois() {
    ParkingPoiDao parkingPoi = new ParkingPoiDao();
    parkingPoi.setParkingPoiId("123");
    em.persist(parkingPoi);

    TypedQuery<ParkingPoiDao> query = em
            .createNamedQuery("ParkingPoiDao.findById", ParkingPoiDao.class)
            .setParameter("parkingPoiId", "123");
    List<ParkingPoiDao> pPoiDaos = query.getResultList();

    assertThat(pPoiDaos).hasSize(1);

    query = em.createNamedQuery("ParkingPoiDao.findAll", ParkingPoiDao.class);
    pPoiDaos = query.getResultList();

    assertThat(pPoiDaos).hasSize(1);
}
 

Не могли бы вы подтвердить, в чем разница с вашими сущностями, и, возможно, добавить подробную информацию о том, как вы сохраняете свои ParkingPoiDao сущности?

Комментарии:

1. У меня уже есть собственность parkingPoiId в ParkingPoiDao. Я думаю, что проблема основана на том факте, что столбец poiType (который является столбцом дискриминатора) в PoiDao является перечислением !??

2. Я не уверен, что понимаю вас. discriminatorType Принимает a javax.persistence.DiscriminatorType (который является перечислением), но это сделано специально. Если это все еще не работает, возможно, вы можете разместить пример проекта на GitHub или что-то, на что можно взглянуть?

Ответ №2:

Я реализую объединенное наследование с несколькими таблицами. Объединенное наследование является наиболее логичным решением для наследования, поскольку оно отражает объектную модель в модели данных. В объединенном наследовании для каждого класса в иерархии наследования определяется таблица для хранения только локальных атрибутов этого класса. Каждая таблица в иерархии также должна хранить идентификатор объекта (первичный ключ), который определен только в корневом классе. Все классы в иерархии должны иметь один и тот же атрибут id. Столбец дискриминатора используется для определения, к какому классу принадлежит конкретная строка, каждый класс в иерархии определяет свое собственное уникальное значение дискриминатора.

Проблема заключалась в том, что мне пришлось добавить аннотацию @ObjectTypeConverter на уровне класса, а также аннотацию @Convert на уровне поля:

 @ObjectTypeConverters({
    @ObjectTypeConverter (
            name="poiTypeConverter",
            dataType=java.lang.String.class,
            objectType=ServiceTypeEnum.class,
            conversionValues={
                @ConversionValue(dataValue="CHARGING", objectValue="CHARGING"),
                @ConversionValue(dataValue="PARKING", objectValue="PARKING")
            }
    )
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="poiType", discriminatorType=DiscriminatorType.STRING)
@Table(name="pois")
public abstract class PoiDao implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="poiId")
    private int poiId;
    @Convert("poiTypeConverter")
    private ServiceTypeEnum poiType;
...

@Entity
@DiscriminatorValue("PARKING")
@Table(name="parkingPois")
@NamedQueries({
    @NamedQuery(name="ParkingPoiDao.findAll", query="SELECT p FROM ParkingPoiDao p"), 
    @NamedQuery(name="ParkingPoiDao.findById", query="SELECT p FROM ParkingPoiDao p WHERE p.parkingPoiId = :parkingPoiId")
})
public class ParkingPoiDao extends PoiDao implements Serializable {
    //@Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id")
    private int id;
    @Column(name="parkingPoiId")
    private String parkingPoiId;
    @Column(name="poiId")
    @Convert("parkingPoiStatusConverter")
    @Column(name="status")
    private ParkingPoiStatusEnum status;
    ...
}
 

Конечно, соответствующие значения должны быть в базе данных, если записи уже есть в таблице (таблицах).