Я пытаюсь создать поиск, в котором я выбираю строки из изображения с условиями для столбцов в таблице изображений и ключевые слова / теги из другой таблицы, сопоставленной с помощью отношения «многие ко многим».Изображение может иметь несколько тегов, а теги могут быть связаны с несколькими изображениями.
Таблицы:
**Image**
imageId
make
model
and so on....
**ImageTags**
imageId
tagId
**Tags**
tagId
tagName
Скажем, я хочу найти изображения с тегом "nature", SQL будет выглядеть так:
SELECT DISTINCT i.* FROM Images i
INNER JOIN ImagesTags it ON it.imageId = i.imageId
INNER JOIN Tags t ON t.tagId = it.tagId
WHERE t.tagName in ("city", "nature");
Может быть больше идругие условия в предложении WHERE для других столбцов таблицы Image, и поэтому я попытался построить динамические запросы с помощью API Criteria, поскольку условия будут смещаться при каждом запросе.Но я не могу заставить его работать.
Мне удалось только найти ключевое слово:
@Transactional
public List<Image> findByKeyword(String [] tags) {
List<Image> images = null;
try (Session session = entityManager.unwrap(Session.class)){
String hql = "select distinct i from Image i " +
"join i.tags t " +
"where t.tagName in (:tags)";
Query query = session.createQuery(hql);
((org.hibernate.query.Query) query).setParameterList("tags", tags);
images = query.getResultList();
} catch (Exception ex) {
ex.printStackTrace();
}
return images;
}
Теперь я хочу добавить дополнительные условия в предложение WHERE, например:
SELECT DISTINCT i.* FROM Images i
INNER JOIN ImagesTags it ON it.imageId = i.imageId
INNER JOIN Tags t ON t.tagId = it.tagId
WHERE i.make = "Nikon" AND t.tagName in ("city", "nature");
Я пытался создать построитель и добавить предикаты, но не могу найти способ создания объединения.
CriteriaBuilder cBuilder = session.getCriteriaBuilder();
CriteriaQuery<Image> criteriaQuery = cBuilder.createQuery(Image.class);
Root<Image> imageRoot = criteriaQuery.from(Image.class);
predicateList.add(cBuilder.equal(imageRoot.get("imageId"), sc.getImageId()));
predicateList.add(cBuilder.equal(imageRoot.get("licenseType"), sc.getLicenseType()));
//more predicates are omitted
//Here somewhere I want to add an array or list of tags to the where clause and match that to the many-to-many relationship.
Predicate finalPredicate = cBuilder.and(predicateList.toArray(new Predicate[0]));
criteriaQuery.where(finalPredicate).distinct(true);
org.hibernate.query.Query<Image> imageQuery = session.createQuery(criteriaQuery);
List<Image> images = imageQuery.getResultList();
Класс изображения:
@Entity
@Table(name = "Images")
public class Image implements File {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "imageId")
private int imageId;
@Column(name = "fileName")
private String fileName;
@Column(name = "filePath")
private String filePath;
@Column(name = "description")
private String description;
@Column(name = "fileSize")
private String fileSize;
@Column(name = "dateTime")
private LocalDateTime dateTime;
//Other attributes omitted
@ManyToMany
@JoinTable(
name = "ImagesTags",
joinColumns = @JoinColumn(name = "imageId"),
inverseJoinColumns = @JoinColumn( name = "tagId"))
private Set<Tag> tags;
//getter and setters omitted
Класс тегов:
@Entity
@Table(name = "Tags")
public class Tag {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "tagId")
private int tagId;
@Column(name = "tagName")
private String tagName;
@ManyToMany
@JoinTable(
name = "ImagesTags",
joinColumns = @JoinColumn(name = "tagId"),
inverseJoinColumns = @JoinColumn( name = "imageId"))
private List<Image> images;
Как мне создать это объединение и добавить ключевые слова в предложение "WHERE tagName IN"?
Редактировать:
Я изменил код на этот, но он все равно не работает
CriteriaBuilder cBuilder = session.getCriteriaBuilder();
CriteriaQuery<Image> criteriaQuery = cBuilder.createQuery(Image.class);
Root<Image> imageRoot = criteriaQuery.from(Image.class);
Root<Tag> tagRoot = criteriaQuery.from(Tag.class);
Join<Image, Tag> join = imageRoot.join(Image_.TAGS);
List<Predicate> predicateList = new ArrayList<>();
predicateList.add(cBuilder.equal(imageRoot.get("width"), 2000));
predicateList.add(cBuilder.in(join));
predicateList.add(cBuilder.equal(tagRoot.get("tagName"), tags[0]));
Predicate finalPredicate = cBuilder.and(predicateList.toArray(new Predicate[0]));
criteriaQuery.select(imageRoot);
criteriaQuery.where(finalPredicate).distinct(true);
org.hibernate.query.Query<Image> imageQuery = session.createQuery(criteriaQuery);
List<Image> images = imageQuery.getResultList();
Редактировать 2
Попытка с этим:
CriteriaBuilder cBuilder = session.getCriteriaBuilder();
CriteriaQuery<Image> criteriaQuery = cBuilder.createQuery(Image.class);
Root<Image> imageRoot = criteriaQuery.from(Image.class);
Root<Tag> tagRoot = criteriaQuery.from(Tag.class);
Join<Image, Tag> join = imageRoot.join(Image_.TAGS);
List<Predicate> predicateList = new ArrayList<>();
predicateList.add(cBuilder.in(join));
predicateList.add(cBuilder.or(cBuilder.equal(tagRoot.get("tagName"), "träd")));
Predicate finalPredicate = cBuilder.and(predicateList.toArray(new Predicate[0]));
criteriaQuery.select(imageRoot);
criteriaQuery.where(finalPredicate).distinct(true);
org.hibernate.query.Query<Image> imageQuery = session.createQuery(criteriaQuery);
List<Image> images = imageQuery.getResultList();
Но это производит (для меня) очень странный запрос к базе данных:
select distinct generatedAlias0
from Image as generatedAlias0,
Tag as generatedAlias1
inner join generatedAlias0.tags as generatedAlias2
where (generatedAlias2 in ()) and (
generatedAlias1.tagName=:param0
)
select distinct image0_.imageId as imageId1_1_,
image0_.author as author16_1_,
image0_.dateTime as dateTime2_1_,
image0_.description as descript3_1_,
image0_.fileName as fileName4_1_,
image0_.filePath as filePath5_1_,
image0_.fileSize as fileSize6_1_,
image0_.height as height7_1_,
image0_.licenseType as licenseT8_1_,
image0_.location as location9_1_,
image0_.make as make10_1_,
image0_.model as model11_1_,
image0_.noOfAllowedUses as noOfAll12_1_,
image0_.price as price13_1_,
image0_.resolution as resolut14_1_,
image0_.width as width15_1_
from
Images image0_
inner join
ImagesTags tags2_
on image0_.imageId=tags2_.imageId
inner join
Tags tag3_
on tags2_.tagId=tag3_.tagId cross
join
Tags tag1_
where(tag3_.tagId in ()) and tag1_.tagName=?