Перерыл весь Inte rnet и пока не нашел подходящего для себя ответа. Я хотел бы применить фильтр к своему проекту: пользователь вводит список цветов и список размеров, и программа возвращает все параметры на основе ввода.
Для этого я использую запрос:
@Query("select distinct clothes FROM Clothes as clothes left join fetch clothes.colors as ccolor left join fetch clothes.sizes as csize where " +
"ccolor.name in (:colors) and csize.name in (:sizes)")
List<Clothes> findAllByColorsInAndSizesIn(List<String> colors, List<String> sizes);
Я видел множество ответов участников, что лучше использовать Set<...>
вместо List<...>
, но я считаю, что это неправда (есть статья об этом от Влада Михалчи ). Использование Set<...>
похоже на использование @Transactional
для прохождения тестов в вашем проекте Spring.
Из упомянутой выше статьи я попытался использовать следующий код в зависимости от моей проблемы:
List<Clothes> clothes = entityManager
.createQuery(
"select distinct clothes FROM Clothes as clothes left join fetch clothes.colors as ccolor where " +
" ccolor.name in (:colors)", Clothes.class)
.setParameter("colors", colors)
.setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
.getResultList();
clothes = entityManager
.createQuery(
"select distinct clothes FROM Clothes as clothes left join fetch clothes.sizes as csize where " +
"csize.name in (:sizes)", Clothes.class)
.setParameter("sizes", sizes)
.setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
.getResultList();
Однако я не думаю, что это правильно, поскольку первый запрос избыточен. Вот доказательство:
Итак, мне пришла в голову идея «вручную» сравнить два массива и объединить их, где размер и цвет одежды соответствуют исходному фильтру.
Мой UML:
Код:
Одежда. java:
@Entity
@Table(name = "clothes")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Clothes {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "clothes_generator")
@SequenceGenerator(name="clothes_generator", sequenceName = "clothes_seq", allocationSize = 1, initialValue = 1)
private Long id;
@Column
private String name;
@ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
@JoinTable(name = "clother_color",
joinColumns = { @JoinColumn(name = "clother_id") },
inverseJoinColumns = { @JoinColumn(name = "color_id") })
private List<Color> colors = new ArrayList<>();
public void addColor(Color color) {
colors.add(color);
color.getClothes().add(this);
}
public void removeColor(Color color) {
colors.remove(color);
color.getClothes().remove(this);
}
@ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
@JoinTable(name = "clother_size",
joinColumns = { @JoinColumn(name = "clother_id") },
inverseJoinColumns = { @JoinColumn(name = "size_id") })
private List<Size> sizes = new ArrayList<>();
public void addSize(Size size) {
sizes.add(size);
size.getClothes().add(this);
}
public void removeSize(Size size) {
sizes.remove(size);
size.getClothes().remove(this);
}
}
Размеры. java:
@Entity
@Table(name = "color")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Color {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "color_generator")
@SequenceGenerator(name="color_generator", sequenceName = "color_seq", allocationSize = 1, initialValue = 1)
private Long id;
@Column
private String name;
@ManyToMany(mappedBy="colors")
private List<Clothes> clothes = new ArrayList<>();
public void addClothes(Clothes clothes) {
this.clothes.add(clothes);
clothes.getColors().add(this);
}
public void removeClothes(Clothes clothes) {
this.clothes.remove(clothes);
clothes.getColors().remove(this);
}
public Color(String name){
this.name = name;
}
}
Цвет. java
@Entity
@Table(name = "color")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Color {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "color_generator")
@SequenceGenerator(name="color_generator", sequenceName = "color_seq", allocationSize = 1, initialValue = 1)
private Long id;
@Column
private String name;
@ManyToMany(mappedBy="colors")
private List<Clothes> clothes = new ArrayList<>();
public void addClothes(Clothes clothes) {
this.clothes.add(clothes);
clothes.getColors().add(this);
}
public void removeClothes(Clothes clothes) {
this.clothes.remove(clothes);
clothes.getColors().remove(this);
}
public Color(String name){
this.name = name;
}
}
Тест, который я пытаюсь пройти (я знаю, что мне нужно использовать assert):
@Test
void findClothesByColorsAndSizes(){
Color colorBlue = new Color("Blue");
Color colorRed = new Color("Red");
Color colorPink = new Color("Pink");
colorRepository.saveAll(Arrays.asList(colorBlue, colorPink, colorRed));
colorRepository.flush();
Size sizeL = new Size("L");
Size sizeXL = new Size("XL");
Size sizeS = new Size("S");
sizeRepository.saveAll(Arrays.asList(sizeL, sizeS, sizeXL));
sizeRepository.flush();
Clothes clothes1 = new Clothes("Clothes1");
clothes1.addColor(colorRepository.findByName(colorBlue.getName()));
clothes1.addSize(sizeRepository.findByName(sizeS.getName()));
Clothes clothes2 = new Clothes("Clothes2");
clothes2.addColor(colorRepository.findByName(colorBlue.getName()));
clothes2.addSize(sizeRepository.findByName(sizeL.getName()));
Clothes clothes3 = new Clothes("Clothes3");
clothes3.addColor(colorRepository.findByName(colorRed.getName()));
clothes3.addSize(sizeRepository.findByName(sizeXL.getName()));
Clothes clothes4 = new Clothes("Clothes4");
clothes4.addColor(colorRepository.findByName(colorPink.getName()));
clothes4.addSize(sizeRepository.findByName(sizeS.getName()));
Clothes clothes5 = new Clothes("Clothes5");
clothes5.addColor(colorRepository.findByName(colorPink.getName()));
clothes5.addSize(sizeRepository.findByName(sizeL.getName()));
clothesRepository.saveAll(Arrays.asList(clothes1, clothes2, clothes3, clothes4, clothes5));
clothesRepository.flush();
for (Clothes clothes: clothesRepository.findAll()){
System.out.println("name: " + clothes.getName());
System.out.println("color: " + clothes.getColors().get(0).getName());
System.out.println("size: " + clothes.getSizes().get(0).getName());
System.out.println();
}
System.out.println();
System.out.println();
System.out.println();
List<String> colors = new ArrayList<>();
colors.add(colorBlue.getName());
colors.add(colorRed.getName());
List<String> sizes = new ArrayList<>();
sizes.add(sizeL.getName());
sizes.add(sizeXL.getName());
// List<Clothes> clothes = clothesRepository.findAllBySizesIn(sizes);
// List<Clothes> common = new ArrayList<>();
// for(Clothes clothesItem : clothesRepository.findAllByColorsIn(colors)){
// if(clothes.contains(clothesItem)){
// common.add(clothesItem);
// }
// }
// System.out.println(common.size());
//
// System.out.println();
// for (Clothes clothesItem : common) {
// System.out.println("name: " + clothesItem.getName());
// System.out.println("color: " + clothesItem.getColors().size());
// System.out.println("size: " + clothesItem.getSizes().size());
// System.out.println();
// }
List<Clothes> clothes = entityManager
.createQuery(
"select distinct clothes FROM Clothes as clothes left join fetch clothes.colors as ccolor where " +
" ccolor.name in (:colors)", Clothes.class)
.setParameter("colors", colors)
.setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
.getResultList();
clothes = entityManager
.createQuery(
"select distinct clothes FROM Clothes as clothes left join fetch clothes.sizes as csize where " +
"csize.name in (:sizes)", Clothes.class)
.setParameter("sizes", sizes)
.setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
.getResultList();
System.out.println(clothes.size());
System.out.println();
for (Clothes clothesItem : clothes) {
System.out.println("name: " + clothesItem.getName());
System.out.println("color: " + clothesItem.getColors().size());
System.out.println("size: " + clothesItem.getSizes().size());
System.out.println();
}
}