#SqlResultSetMapping columns : entities with sub-entities - java

I have Test entity :
public class Test {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "duration", nullable = false)
private int duration;
#Column(name = "test_name", nullable = false, unique = true)
private String testName;
#Column(name = "archived", nullable = false)
private boolean archived;
#OneToMany(mappedBy = "test", fetch = FetchType.EAGER)
private Set<Question> questions;
#ManyToMany(mappedBy = "tests")
private Set<User> users;
Question Entity:
public class Question {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "is_multichoice", nullable = false)
private boolean isMultichoice;
#Column(name = "is_open", nullable = false)
private boolean isOpen;
#Column(name = "picture")
private String picture;
#Column(name = "question")
private String question;
#ManyToOne
#JoinColumn(name = "test_id", nullable = false)
private Test test;
#Column(name = "archived", nullable = false)
private boolean isArchived;
#OneToMany(mappedBy = "question", fetch = FetchType.EAGER)
private Set<Answer> answers;
This Test entity has Set of questions, in such way Question Entity has Set of answers.
I wrote SQL query to get test (The reason why it is not HQL you could find by link Hibernate HQL : no entity found for query) :
#NamedNativeQuery(name = "getCurrentTestById",
query = "SELECT t.id as tId, t.test_name, t.duration, q.id as qId, " +
"q.question as question, q.is_multichoice as is_multichoice, " +
"q.is_open as is_open, a.id as aId, a.answer_text as answer_text FROM result r " +
"JOIN test t ON r.test_id = t.id " +
"JOIN user u ON r.user_id = u.id " +
"JOIN question q ON t.id = q.test_id JOIN answer a ON q.id = a.question_id " +
"WHERE t.id = :testId AND u.id = :userId AND r.permission = :permissionId " +
"AND q.archived = false AND a.archived = false")
Now i need to map it to my entity Test by using #SqlResultSetMapping annotation:
#SqlResultSetMappings({
#SqlResultSetMapping(name="toTest",
entities = {
#EntityResult(entityClass = com.bionic.entities.Test.class, fields = {
#FieldResult(name = "id", column = "tId"),
#FieldResult(name = "test_name", column = "test_name"),
#FieldResult(name = "duration", column = "duration"),
#FieldResult(name = "questions.question", column = "question"),
#FieldResult(name = "questions.id", column = "qId"),
#FieldResult(name = "questions.isMultichoice", column = "is_multichoice"),
#FieldResult(name = "questions.isOpen", column = "is_open"),
#FieldResult(name = "questions.answers.id", column = "aId"),
#FieldResult(name = "questions.answers.answer_text", column = "answer_text"),
})
})
})
I am getting exception :
Caused by: org.hibernate.MappingException: dotted notation reference neither a component nor a many/one to one

This is why frameworks are generally bad news. Instead of using hibernate, you should follow the interface segregation principle. Your application should not know or care about How to select the data you need and what the table names are etc. Simply create a stored procedure that takes this responsibility and call it as opposed to having all the junk code in your app. Then if you want an easy way to map just have your stored proc return json by calling For JSON at the end. Mapping object fields to the JSON object becomes a piece of cake. You will find that with frameworks you spend more time troubleshooting the framework than actually programming.

Related

Passing Queries from Postgres to JPA

I'm newbie
I'm trying pass this Postgres query to JPA/JPQL
SELECT
DISTINCT(srv.code) AS Serv_Cod,
srv.id AS Serv_id,
srv.description AS Serv_Desc
FROM db.Category AS cat
join db.Classification AS cla ON cat.id = cla.cat_id
join db.Service AS srv ON srv.id = cla.srv_id
WHERE cat.id = 10
ORDER BY srv.id;
Now I want to write the same Query, I have the Entities with the same name Table.
Classification
#Entity
#Table(name = "Classification", schema = "db")
#Audited
public class Classification implements Identifiable<Long> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "srv_id", nullable = true)
private Service service;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "cat_id", nullable = true)
private Category category;
....
}
Service
#Entity
#Table(name = "Service", schema = "db")
#Audited
public class Service implements Identifiable<Long> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#Column(name = "code", nullable = false)
private String code;
#Column(name = "description", nullable = false)
private String description;
....
}
I was reading, but I'm very confused...
I don't know how to write the ON for the JOIN, and establish the DISTINCT for a Column/Field.
Long myID = 25L;
this.em.createQuery("SELECT NEW SomeDto(srv.id, srv.code, srv.description)"
+ " FROM Classification cla"
+ "JOIN cla·cat_id cat"
+ "JOIN cla·srv_id srv"
+ "WHERE cat.id = :id"
,BaseObjectDto.class).setParameter("id", myID).getResultList();
Thank you for you valuable Help.
The query is very simple. When you have ToOne relationships you can navigate to the related entity. There is no need to JOIN ON.
Even with ToMany there is no need for the ON because this is already defined in the mapping.
So the query will look like:
SELECT NEW SomeDto(cla.service.id, cla.service.code, cla.service.description)
FROM Classification cla
WHERE category.id = :id

Join queries with JPQL in Spring Data Jpa

I created a left join query with JPQL in spring data jpa but failed in my unit test. There are two entities in the project.
Product entity:
#Entity
#Table(name = "t_goods")
public class Product implements Serializable {
#Id
#GeneratedValue
#Column(name = "id", length = 6, nullable = false)
private Integer id;
#Column(name = "name", length = 20, nullable = false)
private String name;
#Column(name = "description")
private String desc;
#Column(name = "category", length = 20, nullable = false)
private String category;
#Column(name = "price", nullable = false)
private double price;
#Column(name = "is_onSale", nullable = false)
private Integer onSale;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "brand_id")
private Brand brand;
// getter and setter
}
Brand entity:
#Entity
#Table(name = "tdb_goods_brand")
public class Brand implements Serializable {
#Id
#GeneratedValue
#Column(name = "id", length = 6, nullable = false)
private Integer id;
#Column(name = "brand_name", unique = true, nullable = false)
private String name;
#OneToMany(mappedBy = "brand", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<Product> products;
// getter and setter
}
And a third class Prod to map the query results to Object:
public class Prod implements Serializable {
private Integer id;
private String name;
private double price;
//private String brandName;
// getter and setter
}
It works fine with this query:
public interface ProductRepository extends JpaRepository<Product, Integer> {
#Query(value = "select new com.pechen.domain.Prod(p.id, p.name, p.price) from Product p ")
Page<Prod> pageForProd(Pageable pageRequest);
}
But if I add new property brandName for Prod and refactor the query with left join, it test fails:
#Query(value = "select new com.pechen.domain.Prod(p.id, p.name, p.price, b.name) from Product p left join com.pechen.domain.Brand b on p.brand_id = b.id")
Page<Prod> pageForProd(Pageable pageRequest);
The problem seems to be here on p.brand_id = b.id because there is not a brand_id property in Product, it's just a column name. So how can I make this work?
Update:
There turned to be some sytax errors in the JPQL query, just fix it as the following:
#Query(value = "select new com.pechen.domain.Prod(p.id, p.name, p.price, b.name) from Product p left join p.brand b")
Page<Prod> pageForProd(Pageable pageRequest);
Besides, it's very troublesome in this way to create another class everytime to map the query results into object(I mean the Prod class). So is there a good way to work with it? Any help would be appreciated.
Instead of p.brand_id = b.id you should do p.brand.id = b.id

Hibernate updating with list

I want to update a ManyToMany relation in my update statement.
I'm using Reference class, here is the class :
public class Reference implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO, generator="user_gen")
#SequenceGenerator(name="user_gen", sequenceName="SEQ_USER")
#Column(name = "DOCUMENTID", nullable = false)
private int documentID;
#Column(name = "REFERENCE")
private String reference = "";
#Column(name = "CODE")
private String code = "";
#Column(name = "REMARK")
private String remark = "";
#Column(name = "TITLE")
private String title = "";
#ManyToMany(cascade = CascadeType.ALL, fetch=FetchType.EAGER)
#JoinTable(name = "DOCUMENTS_MACHINES", joinColumns = { #JoinColumn(name = "DOCUMENTID") }, inverseJoinColumns = { #JoinColumn(name = "MACHINEID") })
private Set<Machine> machines = new HashSet<Machine>();
I would like to know if it is possible to update a ManyToMany relations in a HQL statement because session.update(object) would cause conflicts problem because of missing properties.
What I've tried :
String hqlUpdate = "update Reference r " +
"set r.title = :title, " +
"r.machines = :machines " +
"where r.documentID = :id";
int updatedEntities = session.createQuery( hqlUpdate )
.setString("title", reference.getTitle())
.setParameterList("machines", reference.getMachines())
.setInteger("id", reference.getDocumentID())
.executeUpdate();
However, it doesn't work, so my question is : Is it possible to update a collection and how ?
Thanks
Check that many to many hibernate update mapping query example:
many to many hibernate update
Also have a look at CascadeType. You can set the behaviour for save/update operations directly by using the CascadeType in the relationship annotation.

Hibernate Exception - could not locate named parameter

i am trying to extract a list of objects from database from entity (table) StudySeries:
#Entity
#Table(name="StudySeries", uniqueConstraints = {
#UniqueConstraint(columnNames = "SeriesInstanceUID")})
public class StudySeries implements Serializable {
...
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "SeId", unique = true, nullable = false)
private Long seId;
#Column(name="SeriesInstanceUID", unique=true, nullable = false)
private String seriesInstanceUID;
...
#ManyToOne
#JoinColumn(name = "StId", referencedColumnName="StId")
private StudyDetails studyDetails;
...
}
This entity is N-1 joined with StudyDetails (on StudyDetails has many StudySeries):
#Entity
#Table(name="StudyDetails", uniqueConstraints = #UniqueConstraint(columnNames = "StudyInstanceUID"))
public class StudyDetails implements Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name="StId", unique = true, nullable = false)
private Long stId;
#Column(name="StudyInstanceUID", unique=true, nullable = false)
private String studyInstanceUID;
...
#OneToMany(fetch = FetchType.LAZY, mappedBy = "studyDetails", cascade = CascadeType.ALL)
private Set<StudySeries> studySeries = new HashSet<StudySeries>(0);
...
}
In my StudySeriesDAOImpl() i am trying to:
#Override
public List<StudySeries> getStudySeriesObjectsByStudyId(Long stId) {
List<StudySeries> results=new ArrayList<>();
Session s=HibernateUtil.openSession();
s.beginTransaction();
String hql = "from StudySeries E where E.studyDetails.stId = stId";
Query query = s.createQuery(hql);
query.setParameter("stId", stId);
results = query.list();
s.getTransaction().commit();
s.close();
log.info(">>>>> list size: " + results.size());
return results;
}
I have also tried the hql query as:
String hql = "from StudySeries E where E.stId = stId";
However i am getting:
org.hibernate.QueryParameterException: could not locate named parameter [stId]
at org.hibernate.engine.query.spi.ParameterMetadata.getNamedParameterDescriptor(ParameterMetadata.java:100) at org.hibernate.engine.query.spi.ParameterMetadata.getNamedParameterDescriptor(ParameterMetadata.java:100)
at org.hibernate.engine.query.spi.ParameterMetadata.getNamedParameterExpectedType(ParameterMetadata.java:106)
at org.hibernate.internal.AbstractQueryImpl.determineType(AbstractQueryImpl.java:466)
at org.hibernate.internal.AbstractQueryImpl.setParameter(AbstractQueryImpl.java:436)
at com.npap.dao.StudySeriesDAOImpl.getStudySeriesObjectsByStudyId(StudySeriesDAOImpl.java:239)
Any ideas what is wrong?
In the StudySeries class, the id is named as 'seId', not 'stId'.
You should do like this: String hql = "from StudySeries E where E.seId = stId";

JPQL : How to construct a WHERE clause?

i would like to create a namedquery in JPQL, but i don't understand how it's working...
Here my entity:
#Entity
#NamedQueries({
#NamedQuery(name = "Translation.lang",
query = "SELECT t FROM Translation t WHERE t.reference.id = :refId AND t.language.lang = :lang")
})
#Table(name = "T_E_TRANSLATION_TRL")
public class Translation implements java.io.Serializable {
#Id
#Column(name = "TRL_ID", unique = true, nullable = false)
#TableGenerator(name="translationSeqStore",
table="T_S_APP_SEQ_STORE_AST",
pkColumnName="AST_SEQ_NAME",
valueColumnName = "AST_SEQ_VALUE",
pkColumnValue = "T_E_TRANSLATION_TRL.TRL_ID",
allocationSize=1)
#GeneratedValue(strategy=GenerationType.TABLE,
generator="translationSeqStore")
private Integer id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "TRL_REF_ID", nullable = false)
private Reference reference;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "TRL_LAN_ID", nullable = false)
private Language language;
#Column(name = "TRL_LABEL", nullable = false, length = 4000)
private String label;
Should i use LEFT JOIN on Reference & Language to select my translatation with these id ?
Thank you.
I think you want:
SELECT t FROM Translation t join fetch t.reference join fetch t.language WHERE t.reference.id = :refId AND t.language.lang = :lang
That will join (and fetch the LAZY reference and language) and return the Translations for the reference with ID refId and language with lang = lang.

Categories