Проблема сопоставления Java JPA с вложенными коллекциями - PullRequest
0 голосов
/ 31 октября 2019

У меня следующая проблема: у меня есть три связанных класса. Я их аннотировал, но получаю неправильные результаты (описано ниже):

@Entityd
@Table(name = "ClassA")
public class ClassA{
    @Id
    @GeneratedValue
    private Long id = 0L;
    ...
    @OneToMany(fetch = FetchType.EAGER,cascade=CascadeType.ALL)
    @Fetch(FetchMode.SELECT)
    @Column(name = "ClassBList")
    private List<ClassB> listB;
    ...
}

@Entity
@Table(name="ClassB")
public class ClassB {
     @Id
     @GeneratedValue
     private Long id = 0L;
     ...
     @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
     @Fetch(FetchMode.SELECT)
     @Column(name = "ClassCList")
     private List<ClassC> listC;
     ...
}

@Entity
@Table(name="ClassC")
public class ClassC  {
  @Id
  @GeneratedValue()
  private Long id = 0L;
  ...
  @ElementCollection
  private List<String> listD;
  ...
}

Когда я работаю с этой структурой для первого ClassA, который я создаю, сохраняю и загружаю, все в порядке. Для нового экземпляра ClassA, который я сохраняю для репо и загрузки снова, у меня неожиданно появляются строки первого ClassA в listD.

В результате мне нужно сохранить каждый класс «независимо». Таким образом, коллекции каждого класса должны содержать уникальные (каждый со своим идентификатором и подсписками) объекты.

Каков наилучший способ (аннотации) для моделирования этих классов в Java 8 с Spring Boot 2.2.0. M5 и javax.persistence-api 2.2?

РЕДАКТИРОВАТЬ:

Теперь я удалил класс B и переписал класс A так:

@Entity
@Table(name = "ClassA")
public class ClassA{
    @Id
    @GeneratedValue
    private Long id = 0L;
    ...
    @OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, cascade = CascadeType.ALL)
    @MapKey(name = "type")
    private Map<String,Set<ClassC>> classCmap;
    ...
}

Thisвыдаёт мне ошибку вроде:

org.hibernate.AnnotationException: Use of @OneToMany or @ManyToMany targeting an unmapped class

Как мне смоделировать / решить / аннотировать это?

Ответы [ 2 ]

1 голос
/ 31 октября 2019

Если вам не нужно запрашивать данные на основе listD, я бы предложил сохранить список в виде текста в базе данных и использовать конвертер:

@Converter
public class ListDConverter implements AttributeConverter<List<String>, String> {

 private ObjectMapper objectMapper = new ObjectMapper();

 @Override
 public String convertToDatabaseColumn(List<String> listD) {
     try {
       return objectMapper.writeValueAsString(listD);
     } catch(IOException e){
        return null;
     }
 }

 @Override
 public List<String> convertToEntityAttribute(String stringListD) {
     if(stringListD == null){
        return Collections.emptyList();
     }
     try {
        return objectMapper.readValue(stringListD, new TypeReference<List<String>>() {});
      }catch(IOException e){
        return Collections.emptyList();
     }
 }

}

и в вашем классе сущностей ClassC:

@Convert(converter = ListDConverter.class)
private List<String> listD;

Почему мне нравится такой подход:

  1. Нет дополнительных таблиц и объединений => лучшая производительность
  2. Легче читать listD в базе данных
0 голосов
/ 31 октября 2019

@ ElementCollection описывает таблицу. Таким образом, ваш код, вероятно, создает таблицу «listD» с одним столбцом типа string без первичного ключа.

Кроме того, вы действительно хотите использовать режим выборки SELECT? Это будет генерировать запросы 1 + b + b * c, когда вы можете просто реализовать свои данные как наборы (поскольку у вас есть уникальные идентификаторы) и использовать JOIN, что приведет к одному и только одному запросу.

См. этот сайт для объяснения того, как использовать @ ElementCollection.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...