Trying to use SQL Function in hibernate - java

I am trying to call My-SQL function which is returning calculated value based on input parameters. I am using native queries for this purpose, I am able to get all fields except calculated field. I am always getting NULL as value for calculated field. Moreover If I execute same query in SQL Client, it gives proper result.
Test.class
#NamedNativeQueries({
#NamedNativeQuery(
name = "getTestData",
query = "Select test_id, BillType, Description, Material, Netvalue1, "
+ "NetValue(billType, Netvalue1) as Sales_Rs "
+ "from test1",
resultClass = Test.class
)
})
#Entity
#Table(name="TEST1")
public class Test {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name="TEST_ID")
private Integer test_id;
#Column(name="Billtype")
private String Billtype;
#Column(name="Description")
private String Description;
#Column(name="Material")
private String Material;
#Column(name="Netvalue1")
private Double Netvalue1;
#Transient
private Double Sales_Rs;
// getters and setters
.
.
.
};
Here is how I am calling native query:
#SuppressWarnings("unchecked")
#Override
public List<Test> getAllTestData() throws MyAppException {
List<Test> result;
try {
Session session = sessionFactory.getCurrentSession();
Query query = session.getNamedQuery("getTestData");
result = query.list();
} catch (DataAccessException e) {
throw new MyAppException("Could not add a new record :", e);
}
return result;
}
Here is Stored function:
CREATE FUNCTION NetValue(billType CHAR(30), Netvalue1 DOUBLE) RETURNS double
BEGIN
Declare RetValue DOUBLE;
SET RetValue =
CASE billType
WHEN 'A' THEN 0.10 * Netvalue1
WHEN 'B' THEN 0.05 * Netvalue1
WHEN 'C' THEN 0.025 * Netvalue1
ELSE Netvalue1
END;
RETURN RetValue;
END;

You declared field Double Sales_Rs as transient, therefore it is not handled by Hibernate.
See this thread for two solutions:
a) Use a Hibernate specific mapping to calculate Sales_RS by a formula which calls your database function:
#Formula("NetValue(billType, Netvalue1)")
private Double Sales_Rs;
b) use the JPA #Postload annotation to calculate Sales_RS after the object has been loaded:
#Transient
private Double Sales_Rs;
#PostLoad
private void onLoad() {
Sales_Rs = ... // same logic as in your db function
}
In both cases you can drop the native query and use simple hql:
#NamedQueries({
#NamedQuery(
name = "getTestData",
query = "from Test"
)})

Related

How to implement Server-side processing of DataTables with JDBC so that it paginates?

I have a Spring Boot app with DataTables server-side processing and Oracle database. Actually, I started with implementing one of the tutorials. It worked. The tutorial uses JPA. I want to implement the same using JDBC. I made all the corresponding classes, the repository, the new model with same filds but without jpa. But when I tried to fetch the data, it allowed me to get only the first page without a chance to get to the second page. Below I will post the extracts of the original and added code. So, the original tutorial used these classes:
#Entity
#Table(name = "MYUSERS")
public class User {
#Id
#Column(name = "USER_ID")
private Long id;
#Column(name = "USER_NAME")
private String name;
#Column(name = "SALARY")
private String salary;
...getters and setters
}
And
#Entity
public class UserModel {
#Id
private Long id;
private String name;
private String salary;
private Integer totalRecords;
#Transient
private Integer rn;
...getters and setters
}
And I substituted these two classes with one like this:
public class NewUser {
private Long id;
private String name;
private String salary;
private Integer totalRecords;
private Integer rn;
...getters and setters
}
The table itself has only 3 fields: id, name and salary, the other 2 fields are created and filled later.
The repositiry the original Author has for the user looks like this:
public interface UserRepository extends JpaRepository<User, Long> {
#Query(value = "SELECT * FROM MYUSERS", nativeQuery = true)
List<User> findAllByUsernames(List<String> listOfUsernames);
}
My own repository looks like this:
#Repository
public class NewUserRepoImpl extends JdbcDaoSupport implements NewUserRepo {
private static final String SELECT_ALL_SQL = "SELECT USER_ID as id, USER_NAME as name, SALARY as salary FROM MYUSERS";
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private final JdbcTemplate jdbctemplate;
public NewUserRepoImpl(NamedParameterJdbcTemplate namedParameterJdbcTemplate, JdbcTemplate jdbctemplate, DataSource dataSource) {
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
this.jdbctemplate = jdbctemplate;
setDataSource(dataSource);
}
#Override
public List<NewUser> findAll(PaginationCriteria pagination) {
try {
String paginatedQuery = AppUtil.buildPaginatedQueryForOracle(SELECT_ALL_SQL, pagination);
return jdbctemplate.query(paginatedQuery, newUserRowMapper());
} catch (DataAccessException e) {
throw new EntityNotFoundException("No Entities Found");
}
}
#Bean
public RowMapper<NewUser> newUserRowMapper() {
return (rs, i) -> {
final NewUser newUser = new NewUser();
newUser.setId(rs.getLong("ID"));
newUser.setName(rs.getString("NAME"));
newUser.setSalary(rs.getString("SALARY"));
newUser.setTotalRecords(rs.getInt("TOTAL_RECORDS"));
newUser.setTotalRecords(rs.getInt("RN"));
return newUser;
};
}
}
the buildPaginatedQueryForOracle thing transforms my Query and allows it to get the totalRecords and rn. Below I will post the output of it both for the orifinal and my queries (they are the same, I checked).
So, the main part, the controller. I left the old and new pieces in it for now for debug purposes and just returning one of the results:
#RequestMapping(value="/users/paginated/orcl", method=RequestMethod.GET)
#ResponseBody
public String listUsersPaginatedForOracle(HttpServletRequest request, HttpServletResponse response, Model model) {
DataTableRequest<User> dataTableInRQ = new DataTableRequest<User>(request);
System.out.println(new Gson().toJson(dataTableInRQ));
DataTableRequest<NewUser> dataTableInRQNew = new DataTableRequest<NewUser>(request);
System.out.println(new Gson().toJson(dataTableInRQNew));
PaginationCriteria pagination = dataTableInRQ.getPaginationRequest();
System.out.println(new Gson().toJson(pagination));
PaginationCriteria paginationNew = dataTableInRQNew.getPaginationRequest();
System.out.println(new Gson().toJson(paginationNew));
String baseQuery = "SELECT USER_ID as id, USER_NAME as name, SALARY as salary FROM MYUSERS";
String paginatedQuery = AppUtil.buildPaginatedQueryForOracle(baseQuery, pagination);
String paginatedQueryNew = AppUtil.buildPaginatedQueryForOracle(baseQuery, paginationNew);
System.out.println(paginatedQuery);
System.out.println(paginatedQueryNew);
Query query = entityManager.createNativeQuery(paginatedQuery, UserModel.class);
System.out.println("Query:");
System.out.println(query);
#SuppressWarnings("unchecked")
List<UserModel> userList = query.getResultList();
System.out.println(new Gson().toJson(userList));
#SuppressWarnings("unchecked")
List<NewUser> userListNew = newUserRepo.findAll(paginationNew);
System.out.println(new Gson().toJson(userListNew));
DataTableResults<UserModel> dataTableResult = new DataTableResults<UserModel>();
DataTableResults<NewUser> dataTableResultNew = new DataTableResults<NewUser>();
dataTableResult.setDraw(dataTableInRQ.getDraw());
dataTableResultNew.setDraw(dataTableInRQNew.getDraw());
dataTableResult.setListOfDataObjects(userList);
dataTableResultNew.setListOfDataObjects(userListNew);
if (!AppUtil.isObjectEmpty(userList)) {
dataTableResult.setRecordsTotal(userList.get(0).getTotalRecords()
.toString());
if (dataTableInRQ.getPaginationRequest().isFilterByEmpty()) {
dataTableResult.setRecordsFiltered(userList.get(0).getTotalRecords()
.toString());
} else {
dataTableResult.setRecordsFiltered(Integer.toString(userList.size()));
}
}
if (!AppUtil.isObjectEmpty(userListNew)) {
dataTableResultNew.setRecordsTotal(userListNew.get(0).getTotalRecords()
.toString());
if (dataTableInRQ.getPaginationRequest().isFilterByEmpty()) {
dataTableResultNew.setRecordsFiltered(userListNew.get(0).getTotalRecords()
.toString());
} else {
dataTableResultNew.setRecordsFiltered(Integer.toString(userListNew.size()));
}
}
System.out.println(new Gson().toJson(dataTableResult));
System.out.println(new Gson().toJson(dataTableResultNew));
return new Gson().toJson(dataTableResult);
}
So, I log out everything possible in the console. Here is the output:
{"uniqueId":"1579786571491","draw":"1","start":0,"length":5,"search":"","regex":false,"columns":[{"index":0,"data":"id","name":"ID","searchable":true,"orderable":true,"search":"","regex":false,"sortDir":"ASC"},{"index":1,"data":"name","name":"Name","searchable":true,"orderable":true,"search":"","regex":false},{"index":2,"data":"salary","name":"Salary","searchable":true,"orderable":true,"search":"","regex":false}],"order":{"index":0,"data":"id","name":"ID","searchable":true,"orderable":true,"search":"","regex":false,"sortDir":"ASC"},"isGlobalSearch":false,"maxParamsToCheck":3}
{"uniqueId":"1579786571491","draw":"1","start":0,"length":5,"search":"","regex":false,"columns":[{"index":0,"data":"id","name":"ID","searchable":true,"orderable":true,"search":"","regex":false,"sortDir":"ASC"},{"index":1,"data":"name","name":"Name","searchable":true,"orderable":true,"search":"","regex":false},{"index":2,"data":"salary","name":"Salary","searchable":true,"orderable":true,"search":"","regex":false}],"order":{"index":0,"data":"id","name":"ID","searchable":true,"orderable":true,"search":"","regex":false,"sortDir":"ASC"},"isGlobalSearch":false,"maxParamsToCheck":3}
{"pageNumber":0,"pageSize":5,"sortBy":{"mapOfSorts":{"id":"ASC"}},"filterBy":{"mapOfFilters":{},"globalSearch":false}}
{"pageNumber":0,"pageSize":5,"sortBy":{"mapOfSorts":{"id":"ASC"}},"filterBy":{"mapOfFilters":{},"globalSearch":false}}
SELECT * FROM (SELECT FILTERED_ORDERED_RESULTS.*, COUNT(1) OVER() total_records, ROWNUM AS RN FROM (SELECT BASEINFO.* FROM ( SELECT USER_ID as id, USER_NAME as name, SALARY as salary FROM MYUSERS ) BASEINFO ) FILTERED_ORDERED_RESULTS ORDER BY id ASC ) WHERE RN > (0 * 5) AND RN <= (0 + 1) * 5
SELECT * FROM (SELECT FILTERED_ORDERED_RESULTS.*, COUNT(1) OVER() total_records, ROWNUM AS RN FROM (SELECT BASEINFO.* FROM ( SELECT USER_ID as id, USER_NAME as name, SALARY as salary FROM MYUSERS ) BASEINFO ) FILTERED_ORDERED_RESULTS ORDER BY id ASC ) WHERE RN > (0 * 5) AND RN <= (0 + 1) * 5
Query:
org.hibernate.query.internal.NativeQueryImpl#3ea49a4
[{"id":3,"name":"user3","salary":"300","totalRecords":18},{"id":4,"name":"user4","salary":"400","totalRecords":18},{"id":5,"name":"user5","salary":"500","totalRecords":18},{"id":6,"name":"user6","salary":"600","totalRecords":18},{"id":7,"name":"user7","salary":"700","totalRecords":18}]
[{"id":3,"name":"user3","salary":"300","totalRecords":1},{"id":4,"name":"user4","salary":"400","totalRecords":2},{"id":5,"name":"user5","salary":"500","totalRecords":3},{"id":6,"name":"user6","salary":"600","totalRecords":4},{"id":7,"name":"user7","salary":"700","totalRecords":5}]
{"draw":"1","recordsFiltered":"18","recordsTotal":"18","data":[{"id":3,"name":"user3","salary":"300","totalRecords":18},{"id":4,"name":"user4","salary":"400","totalRecords":18},{"id":5,"name":"user5","salary":"500","totalRecords":18},{"id":6,"name":"user6","salary":"600","totalRecords":18},{"id":7,"name":"user7","salary":"700","totalRecords":18}]}
{"draw":"1","recordsFiltered":"1","recordsTotal":"1","data":[{"id":3,"name":"user3","salary":"300","totalRecords":1},{"id":4,"name":"user4","salary":"400","totalRecords":2},{"id":5,"name":"user5","salary":"500","totalRecords":3},{"id":6,"name":"user6","salary":"600","totalRecords":4},{"id":7,"name":"user7","salary":"700","totalRecords":5}]}
It helped me realize that:
DataTableRequest incoming from the back is the same for both jpa
and jdbc
PaginationCriteria are also the same
paginatedQuery
having been made with the method specified above are the same.
Differences are already seen in the Lists: where the Jpa list
retrieved with native Query has totalRecords as 18 for every row,
the JDBC repo with the same query returns 1,2,3... for every
subsequent row.
It made me think that I should look at the Query made for JPA. But, as you see in the log, System.out.println wasn't able to decipher it for some reason.
Any advice on how to decipher it and more importantly how to get the right total result for each row would be greatly appreciated!!!

Common functions for oracle and mysql?

In below query I wanted to group by just on date not time that's why I used TO_DATE function
select TO_DATE(e.created_dt, 'dd-mm-yy'),sum(CURRENT_BAL) from sbill.act_resource_t e group by TO_DATE(e.created_dt, 'dd-mm-yy');
so as of now its working fine with oracle but as per our business requirements application should support both oracle and mysql without write two different queries;
so do we have any solution for that which should works with both oracle and mysql ?
Note :- I am using hql
Below code :
Query query1 = entityManager.createQuery("select TO_DATE(e.createdDt, 'dd-mm-yy'),sum(CURRENT_BAL) from ActT e group by TO_DATE(e.createdDt, 'dd-mm-yy')");
List<Object> result=query1.getResultList();
Since the functions differ between the databases, we need a dynamic query. But we can do it efficiently by creating a custom conversion method, which will select the right implementation based on the current database type. And the query itself will remain common (The solution uses FluentJPA library):
public static final FormatModel DD_MM_YY = Format.dateModel(Format.DD, Format.MM, Format.YY);
public static boolean isOracle() {
return false; //should return the actual value in runtime
}
#Local
// picks the right implementation
public static Function1<String, Date> AS_DATE() {
if (isOracle())
return s -> TO_DATE(s, DD_MM_YY); //oracle
return s -> STR_TO_DATE(s, "%d-%m-%y"); // mysql
}
Now we can write a generic implementation:
#Entity
#Table(name = "act_resource_t", schema = "sbill")
#Data
public static class ActResource {
#Id
private int id;
private int currentBAL;
private String createdDT;
}
// for the result
#Tuple
#Data
public static class BalanceByDate {
private Date date;
private int balance;
}
...
public BalanceByDate balanceByDate() {
FluentQuery query = FluentJPA.SQL((ActResource e) -> {
// with lambda we inject the right implementation
Date createdDate = alias(AS_DATE().apply(e.getCreatedDT()), BalanceByDate::getDate);
Integer balance = alias(SUM(e.getCurrentBAL()), BalanceByDate::getBalance);
SELECT(createdDate, balance);
FROM(e);
GROUP(BY(createdDate));
});
return query.createQuery(em, BalanceByDate.class).getSingleResult();
}
This is the resulting SQL for MySQL:
SELECT STR_TO_DATE(t0.created_dt, '%d-%m-%y') AS date, SUM(t0.current_bal) AS balance
FROM sbill.act_resource_t t0
GROUP BY STR_TO_DATE(t0.created_dt, '%d-%m-%y')

JPA limits `queryResultList` even though `setMaxResults` is not definied

I have written the following code snippet to fetch records of certain zip files from zips table using hibernate as the JPA provider.
public List<ZipEntity> getZipEntityFromZipName(String zipName, String version, String createdBy,
String type) throws FileException {
int numAttempts = 0;
do {
numAttempts++;
EntityManager entityManager = getNewEntityManager();
try {
TypedQuery<ZipEntity> query = entityManager
.createNamedQuery(Constants.Database.Queries.GET_FROM_ZIP_NAME, ZipEntity.class)
.setParameter("zipName", zipName)
.setParameter("version", version)
.setParameter("createdBy", createdBy)
.setParameter("type", type);
return query.getResultList();
} catch (PersistenceException e) {
validatePersistenceException(e);
} finally {
closeEntityManager(entityManager);
}
} while (numAttempts <= maxRetries);
throw new FileException("Database connection failed.");
Here are the relevant entity classes
#NamedNativeQueries({
#NamedNativeQuery(
name = Constants.Database.Queries.GET_FROM_ZIP_NAME,
query = Constants.Database.Queries.GET_FROM_ZIP_NAME_QUERY,
resultClass = ZipEntity.class
)
})
#Entity
#Table(name = "zips")
public class ZipEntity {
#EmbeddedId
private ZipKey ZipKey;
public ZipEntity() {
}
public ZipEntity(String zipName, String version, String createdBy, String file, String type,
String extension) {
this.ZipKey = new ZipKey(zipName, version, createdBy, file, type, extension);
}
}
#Embeddable
public class ZipKey implements Serializable {
static final long serialVersionUID = 1L;
#Column(name = "zip_name")
private String zipName;
#Column(name = "version")
private String version;
#Column(name = "created_by")
private String createdBy;
#Column(name = "filepath")
private String file;
#Column(name = "type")
private String type;
#Column(name = "extension")
private String extension;
// Getter, setters and Constructor
}
And the query in Constant class is as follows,
public static final String GET_FROM_ZIP_NAME = "getFile";
public static final String GET_FROM_ZIP_NAME_QUERY = "SELECT * FROM zips WHERE zip_name = " +
":zipName AND version = :version AND created_by = :createdBy AND type = :type";
Event though setMaxResults() is not defined for the above query the results obtained from the above code snippet are limited to 25 record, although the same query executed at DB results in 35 records. What I am doing wrong in here ?
Please debug your solution and check values of "zipName","version","createdBy" and also "type" parameters to verify that they are the expected values by you. This query has for conditions combined by AND logic which affects to your results. To get 35 records, your parameters should make your conditions true for all 35 records.
You can limit the records as below in NamedNativeQuery which provides you 35 records at a time.
#NamedNativeQuery(
name = Constants.Database.Queries.GET_FROM_ZIP_NAME,
query = Constants.Database.Queries.GET_FROM_ZIP_NAME_QUERY,
fetchSize = 35,
resultClass = ZipEntity.class
)

Mapping #ManyToOne / Foreign Key Hibernate Java

First of all, sorry if the subject has already been answered, but i've been searching for almost 6hours in a row, and trying everything i could find on the web, but i'm still stuck..
I Have a problem when i'm executing my code.. I can't find the origin of it, nor a solution...
Here's my different classes: (btw it's my first post on SOF, let me know if you need more information).
I'm going to post my Pojo's, useful DAO's and MySQL table creation orders, and the error message i get.
POJOs:
-Celebrite:
#Entity
#Table(name="Celebrite")
public class Celebrite implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#Column(name="numCelebrite")
#GeneratedValue(strategy=GenerationType.IDENTITY)
#JoinColumn(name="numCelebrite")
private int numCelebrite;
#Column(name="nom")
private String nom;
#Column(name="prenom")
private String prenom;
#Column(name="nationalite")
private String nationalite;
#Column(name="epoque")
private String epoque;
public Celebrite() {
super();
}
public Celebrite(String nom, String prenom, String nationalite, String epoque) {
super();
this.nom = nom;
this.prenom = prenom;
this.nationalite = nationalite;
this.epoque = epoque;
}
public int getNumCelebrite() {
return numCelebrite;
}
public void setNumCelebrite(int numCelebrite) {
this.numCelebrite = numCelebrite;
}
//Other getters/setters
}
-Monument
#Entity
public class Monument implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private String codeM;
private String nomM;
private String proprietaire;
private String typeMonument;
private float latitude;
private float longitude;
public Monument() {
super();
}
public Monument( String codeM,String nomM, String propritaire, String typeMonument, float latitude, float longitude) {
super();
this.codeM=codeM;
this.nomM = nomM;
this.proprietaire = propritaire;
this.typeMonument = typeMonument;
this.latitude = latitude;
this.longitude = longitude;
}
public Monument( String nomM, String propritaire, String typeMonument, float latitude, float longitude) {
super();
this.nomM = nomM;
this.proprietaire = propritaire;
this.typeMonument = typeMonument;
this.latitude = latitude;
this.longitude = longitude;
}
public String getCodeM() {
return codeM;
}
public void setCodeM(String codeM) {
this.codeM = codeM;
}
//other getters/setters..
}
-AssocieA (translation : AssociatedTo)
#Entity
public class AssocieA implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#ManyToOne(fetch=FetchType.LAZY,cascade=CascadeType.ALL)
#JoinColumn(name="numCelebrite",referencedColumnName="numCelebrite")
private Celebrite celebrite;
//private int numCelebrite;
#Id
#ManyToOne(fetch=FetchType.LAZY,cascade=CascadeType.ALL)
#JoinColumn(name="codeM",referencedColumnName="codeM")
//private String codeM;
private Monument monument;
public AssocieA() {
}
public AssocieA(Celebrite celebrite, Monument monument) {
super();
this.celebrite = celebrite;
this.monument = monument;
}
//getters/setters
}
Ok now the DAO, i'm only posting AssocieA's DAO as the others are working perfectly
public class DAOAssocieA {
EntityManagerFactory emf;
EntityManager em ;
public DAOAssocieA() {
super();
this.emf = Persistence.createEntityManagerFactory("jpa-societe-pu");
this.em = emf.createEntityManager();
}
public List<AssocieA> getAssociatedMonuments(int numCelebrite){
Query req=em.createQuery("Select a from AssocieA a where a.numCelebrite =" + numCelebrite);
return req.getResultList();
}
public List<AssocieA> getAssociatedCelebrities(String codeM){
Query req=em.createQuery("Select a from AssocieA a where a.codeM = '"+codeM+"'");
return req.getResultList();
}
}
Finally, the 'main' class
public String execute() {
setDAOc(new DAOCelebrite());
setDAOm(new DAOMonument());
setDAOa(new DAOAssocieA());
if (getNom()==null)
setNom("");
if (getPrenom() == null)
setPrenom("");
if (getNationalite() == null)
setNationalite("");
if (getEpoque()==null)
setEpoque("");
setListeCelebrite(DAOc.getCelebritiesBy(getNom(),getPrenom(),getNationalite(), getEpoque()));
System.out.println(getAssociated());
if (getAssociated().equals("on")) {
for (Celebrite c:listeCelebrite) {
for (AssocieA a : DAOa.getAssociatedMonuments(c.getNumCelebrite())){
System.out.println(a.getCelebrite());
System.out.println(a.getMonument());
}
}
}
return ("success");
-> The return ("success") is because i use Struts2
Now, Table creation orders (on MySQL)
CREATE TABLE Celebrite (numCelebrite int auto_increment, nom varchar(16), prenom varchar(16), nationalite varchar(10), epoque varchar(6), PRIMARY KEY (numCelebrite)) ENGINE=InnoDB;
CREATE TABLE Monument (codeM varchar(5), nomM varchar(25), proprietaire varchar(10), typeMonument varchar(16), longitude float, latitude float, PRIMARY KEY (codeM)) ENGINE=InnoDB;
CREATE TABLE AssocieA (codeM varchar(5), numCelebrite int, PRIMARY KEY (codeM,numCelebrite), FOREIGN KEY (codeM) REFERENCES Monument(codeM), FOREIGN KEY (numCelebrite) REFERENCES Celebrite(numCelebrite)) ENGINE=InnoDB;
To finish, the error message i get:
org.hibernate.QueryException: could not resolve property: numCelebrite of: pojo.AssocieA [Select a from pojo.AssocieA a where a.numCelebrite =1]
I understand that the class 'AssocieA' doesn't have a "numCelebrite" property, but i thought that because of the #ManyToOne annotation, Celebrite Table should be loaded when Associe is loaded.
Else, could you give me some tips to explain how to do that?
The final goal is: having a Celebrite, i'd like, using the numCelebrite, to retrieve every Monuments related to it, using the AssocieA table.
Thank you in advance
EDIT: Solution found on another website by kulturman:
I was using native queries:
em.createQuery("from AssocieA a where a.numCelebrite  =" + numCelebrite);
Instead of JPQL (HQL queries):
em.createQuery("from AssocieA a where a.celebrite.numCelebrite  =" + numCelebrite);
For those who want to see directly the solution, it's in french on OpenClassRoom
Try removing the #JoinColumn(name="numCelebrite") and #GeneratedValue(strategy=GenerationType.IDENTITY) in celebrity pojo, change CascadeType.ALL to CascadeType.Persist and let us know what happen. I'm not an expert but I think that way you can do the trick.
Solution found on another website by kulturman:
I had to replace:
em.createQuery("from AssocieA a where a.numCelebrite =" + numCelebrite);
Instead of JPQL (HQL queries):
by:
em.createQuery("from AssocieA a where a.celebrite.numCelebrite =" + numCelebrite);
Here's the explanation:
I was building my query as if i was requesting my database :
The table AssocieA has the attribute "numCelebrite"
But in my case, I mapped the tables to my classes: Each row of the AssocieA table is now an instance of my AssocieA class.
Using a HQL query, i'm requesting on the instance of my class, not the table of my database.
So what i have to do is a.getCelebrite().getNumCelebrite(), hence the "a.celebrite.numCelebrite"
I hope i've made myself clear enough because my english is not that good.
Here's the link of the forum i had this answer on (it's in french):
https://openclassrooms.com/forum/sujet/org-hibernate-queryexception?page=1#message-92165885

Mapping a composite key with incremented column in Hibernate

I have a PROPERTY table whose primary key is defined as (REF_1_ID, PROPERTY_ID, PROPERTY_IDX) , where PROPERTY_IDX ranges from 0 to n for the same values of (REF_1_ID, PROPERTY_ID) .
I would like to leave it to Hibernate to mange the value of PROPERTY_IDX, so that I can set it to null for new objects and have it populated on save.
What is the most straightforward way of achieving that?
For the same values of (REF_1_ID, PROPERTY_ID)
You can retrieve how many Property Entity with the same (REF_1_ID, PROPERTY_ID) you have
Integer indexValue = (Integer)
session.createQuery("select count(*) from Property p where p.propertyId.rederenceId = :referenceId and p.propertyId.propertyId = :propertyId")
.setParameter("referenceId", referenceId)
.setParameter("propertyId", propertyId)
.iterate()
.next();
Then you set up
propertyId.setIndexValue(indexValue);
You can use an HibernateInterceptor to achieve this funcionality (onSave method) Keep in mind concurrency issues when dealing with this scenario
Or encapsulate as follows
#IdClass(PropertyId.class)
public class Property {
private Integer referenceId;
private Integer propertyId;
private Integer indexValue;
/**
* You can use some repository instead
*
* setUp by using Either constructor Or setter injection
*/
private Session session;
public Property() {}
public Property(Session session) {
this.session = session;
}
#Id
public Integer getIndexValue() {
if(indexValue != null)
return indexValue;
return (Integer)
session.createQuery("select count(*) from Property p where p.propertyId.rederenceId = :referenceId and p.propertyId.propertyId = :propertyId")
.setParameter("referenceId", referenceId)
.setParameter("propertyId", propertyId)
.iterate()
.next();
}
}

Categories