I'm trying to implement a Keyword search functionality that returns a List of Keyword entities based on a field text match.
Right now, the query
select * from photo_keywords pk
inner join keywords k on pk.photo_id = k.keyword_id
inner join photos p on pk.keyword_id = p.photo_id
where k.keyword LIKE "%$SOME_SEARCH_VALUE%";
returns all matching photos for a given keyword search. I'd like to have this adapted to a #NamedQuery with the following Entity objects:
#Entity
#Table(name = "keywords")
public class Keyword implements Serializable{
#Id
#Column(name = "keyword_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column
private String keyword;
#ManyToMany(mappedBy = "keywords")
private List<Photo> photos;
//getters and setters
}
and
#Entity
#Table(name = "photos")
public class Photo implements Serializable{
#Id
#Column(name = "photo_id", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "photo_name", nullable = false)
private String photoName;
#Column(name = "photo_path", nullable = false)
private String photoPath;
#Column(name = "upload_date", nullable = false)
private Date uploadDate;
#Column(name = "view_count", nullable = false)
private int viewCount;
#Column(name = "capture_date", nullable = false)
private Date captureDate;
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "photo_metadata")
#MapKeyColumn(name = "metadata_name")
#Column(name = "metadata_value")
private Map<String, String> photoMetadata;
#ManyToMany
#JoinTable(name = "photo_keywords",
joinColumns = #JoinColumn(name = "keyword_id"),
inverseJoinColumns = #JoinColumn(name = "photo_id"))
public List<Keyword> keywords;
//getters and setters
}
This creates a join table photo_keywords, rather than a JoinColumn.
What I've tried so far with the Keyword entity:
#NamedQueries({
#NamedQuery(
name = "findKeywordByName",
query = "SELECT keyword from Keyword k WHERE k.keyword = :keyword"
)
})
which is executed via
public Keyword findKeywordByString(String keyword){
Keyword thisKeyword;
Query queryKeywordExistsByName = getEntityManager().createNamedQuery("findKeywordByName");
queryKeywordExistsByName.setParameter("keyword", keyword);
try {
thisKeyword = new Keyword((String) queryKeywordExistsByName.getSingleResult());
} catch (NoResultException e){
thisKeyword = null;
}
return thisKeyword;
}
This returns the Keyword, but with the photos property being null. This is to be expected, since I'm only selecting the keyword property. How can I adapt the SQL query above to a #NamedQuery?
Related
I have spring boot project using JPA/Hibernate, MySQL. I have three dao classes that have a many to many relationship.
The Poko classes look like this
Product
#Entity
#Table(name = "product")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false, columnDefinition = "integer")
private Integer id;
#Column(name = "name")
private String name;
#Column(name = "price")
private Double price;
#ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
#JoinTable(
name = "product_extra",
joinColumns = #JoinColumn(name="product_id"),
inverseJoinColumns = #JoinColumn(name="extra_id")
)
private List<Extra> extras = new ArrayList<>();
//constructor getters and setters
}
ProductExtra
#Entity
#Table(name = "product_extra")
public class ProductExtra {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false, columnDefinition = "integer")
private Integer id;
#Column(name = "product_id")
private Integer productId;
#Column(name = "extra_id")
private Integer extraId;
//constructor getters and setter
}
Extra
#Entity
#Table(name = "extra")
public class Extra {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false, columnDefinition = "integer")
private Integer id;
#Column(name = "name")
private String name;
#Column(name = "price")
private Double price;
#ManyToMany(mappedBy = "extras")
private List<Product> products = new ArrayList<>();
//constructor getters and setters
}
The Extra repository with the query
public interface ExtraRepository extends JpaRepository<Extra, Integer> {
#Query("SELECT e.id, e.name, e.price FROM Extra e INNER JOIN ProductExtra pe ON e.id = pe.extraId WHERE pe.productId = ?1")
List<Extra> findExtraById(Integer productId);
}
The mapping in my controller
#GetMapping("/product/{productId}")
public List<Extra>getExtraById(#PathVariable("productId") final Integer productId){
return extraRepository.findExtraById(productId);
}
I am trying to make a many to many query to select The extras in each product, i am however getting this error Failed to convert from type [java.lang.Object[]] to type [#org.springframework.data.jpa.repository.Query the error message surprisingly also contains the results i want. Not sure what am doing wrong
Remove the SELECT clause:
#Query("FROM Extra join e.productExtra WHERE pe.productId = ?1")
Also keep in mind, that you not write an SQL Query, You work on Object, so for join you use the mapped property
I'm using composite PK in my app with 2 tables and one joining table.
I wrote this query for function:
#Repository
public interface HospitalDoctorDao extends JpaRepository<HospitalDoctor, Integer>{
#Query("select hd from HospitalDoctor hd join hospital on hd.hospital_id=hospital.id join doctor on hd.doctor_id = doctor.id where hospital_id = ?1 and doctor_id = ?1")
HospitalDoctor findByHospitalIdAndDoctorId(int hospital_id, int doctor_id);
}
and I am getting error Path expected for file! In MySQL everything is working. How Hibernate works in this case? How I should write this query? Here is my #Entity of join table:
#Entity
#Table(name = "hospital_doctor")
public class HospitalDoctor {
#Embeddable
static class HosdocPK implements Serializable {
private int hospitalId;
private int doctorId;
}
#EmbeddedId
#JsonBackReference
public HosdocPK hosdocPK;
#JsonManagedReference
#MapsId("DoctorId")
#ManyToOne(optional = false)
#JoinColumn(name = "doctorId", referencedColumnName = "id")
private Doctor doctor;
#JsonManagedReference
#MapsId("HospitalId")
#ManyToOne(optional = false)
#JoinColumn(name = "hospitalId", referencedColumnName = "id")
private Hospital hospital;
#Column(name = "Id")
private int id;
#Temporal(TemporalType.DATE)
private Date contract_start_date;
#Temporal(TemporalType.DATE)
private Date contract_end_date;
private String position;
private String supervisor;
private boolean part_time;
Getters and setters
}
Your query is incorrect.
Try:
select hd from HospitalDoctor hd where hd.hospital.id = ?1 and hd.doctor.id = ?2
I would like write this query into HQL :
select DISTINCT * from transportation transp
inner join price p on p.transportationId = transp.transportationId
where p.sectionId = ( select sec.sectionId from section sec where sec.lineId = ( select l.lineId from line l where l.lineId = 1000000000) )
But don't know write subqueries. I know I must use DetachedCriteria.
An other question:
If we can write this query in native query (using createSQLQuery), how can cast returned objet to Transportation entity ?
Thanks
My entities :
#Entity
#Table(name = "transportation")
public class Transportation implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "transportationId")
private Integer id;
#OneToMany(mappedBy = "transportation", fetch = FetchType.EAGER)
#JsonBackReference(value = "price-transportation")
private Set<Price> prices = new HashSet<Price>();
...
}
#Entity
#Table(name = "price")
public class Price implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "priceId")
private Integer id;
#ManyToOne(optional = false)
#JoinColumn(name = "transportationId")
#JsonManagedReference(value = "price-transportation")
private Transportation transportation;
...
}
#Entity
#Table(name = "section")
public class Section implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "sectionId")
private Integer id;
#ManyToOne(optional = false)
#JoinColumn(name = "lineId")
#JsonManagedReference
private Line line;
...
}
#Entity
#Table(name = "line")
public class Line implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "lineId")
private Integer id;
#OneToMany(mappedBy = "line", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JsonBackReference
private Set<Section> sections = new HashSet<Section>();
...
}
I solved my issue by using .addEntity(Transportation.class) like this :
String query = "select DISTINCT * from moyen_transport transp"
+ " join prix_voyage p on p.ID_MoyenTransport = transp.ID_MoyenTransport"
+ " where p.ID_Troncon = ( select t.ID_Troncon from troncon t where t.ID_Troncon = ( select l.ID_Ligne from ligne l where l.ID_Ligne = 1000000000) )";
Query result = getSession().createSQLQuery(query).addEntity(Transportation.class)**;
List<Transportation> results = result.list();
I have two tables
#Entity
#Table(name = "publicSitePortfolioWorks")
public class PublicSitePortfolioWorks implements java.io.Serializable {
#Id
#Column(name = "id")
private Integer id;
#Column(name = "mainImage")
private FrameworkFiles frameworkFilesByMainImage;
#Column(name = "androidImage")
private FrameworkFiles frameworkFilesByAndroidImage;
#Column(name = "bigImage")
private FrameworkFiles frameworkFilesByBigImage;
#Column(name = "mainName")
private String mainName;
#Column(name = "androidName")
private String androidName;
#Column(name = "url")
private String url;
#Column(name = "shortText")
private String shortText;
#Column(name = "`fullText`")
private String fullText;
#Column(name = "linkedObjectNameLocal")
private String linkedObjectNameLocal;
#Column(name = "`sort`")
private Integer sort;
#Column(name = "active")
private Integer active;
#OneToMany
#JoinTable(
name = "framework_files",
joinColumns = {
#JoinColumn(
// table = "framework_files",
name = "linkedObjectName",
referencedColumnName = "linkedObjectNameLocal"),
#JoinColumn(
// table = "framework_files",
name = "linkedObjectId",
referencedColumnName = "id"
)
}
// , inverseJoinColumns = #JoinColumn(name = "linkedObjectName")
)
private Set<FrameworkFiles> filesLocal = new HashSet<FrameworkFiles>(0);
And second table
#Entity
#Table(name = "framework_files")
public class FrameworkFiles implements java.io.Serializable {
#Id
#Column(name = "id")
private Integer id;
#Column(name = "fileName")
private String fileName;
#Column(name = "fileSize")
private Float fileSize;
#Column(name = "filePath")
private String filePath;
#Column(name = "fileUrl")
private String fileUrl;
#Column(name = "linkedObjectId")
private Integer linkedObjectId;
#Column(name = "linkedObjectName")
private String linkedObjectName;
#Column(name = "active")
private Integer active;
#Column(name = "uploadDate")
private Date uploadDate;
#Column(name = "uploadersIP")
private String uploadersIp;
#Column(name = "uploadersIPXFORWARDEDFOR")
private String uploadersIpxforwardedfor;
#Column(name = "userName")
private String userName;
When I have started my application, I got exception:
Caused by: org.hibernate.MappingException: Foreign key (FK_hksv6kkf3cysf5ug30q575tg1:framework_files [filesLocal_id])) must have same number of columns as the referenced primary key (framework_files [linkedObjectName,linkedObjectId,filesLocal_id])
at org.hibernate.mapping.ForeignKey.alignColumns(ForeignKey.java:110)
Please advice, how to fix this exception.
I have seen many topics on stackoverflow about this Exception, but I can't understand, how to fix this error in my code.
I have two classes:
#Entity
public class Tick {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#ManyToOne(optional = false)
#JoinColumn(name = "elitesystem_id", referencedColumnName = "id")
private EliteSystem eliteSystem;
private Date createDate;
#ManyToOne(optional = true)
#JoinColumn(name = "commander_id", referencedColumnName = "id")
private Commander commander;
private String address;
and
#Entity
public class Note {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#ManyToOne(optional = true)
#JoinColumn(name = "tick_id", referencedColumnName = "id")
private Tick tick;
private String text;
private Date createDate;
I want to select all ticks and get notes if there are any:
Query query = session.createQuery("select t, n from Note n right join n.tick t where t.commander.name = '123'");
List<Object[]> list = query.list();
This returns only Tick objects. What is the correct approach to get the Note information as well in 1 single query?
I could put a reference to a Note into the Tick class, but this doesnt sound right, as there are only a few notes, so the column in the Tick table would mostly be empty.
Create a New class for example:
public class TickNote {
private Tick tick;
private Note note;
public TickNote(Tick tick,Note note){
this.tick=tick;
this.note=note;
Then your query is:
Query query = session.createQuery("select NEW TickNote(t, n) from Note n right join n.tick t where t.commander.name = '123'");
List<TickNote> list = query.list();