Get Hibernate Entity instance from id column in SQLQuery result - java

I have (non-Hibernated) database tables that contain ids for Hibernate entities. I can query them (using createSQLQuery), which gives me the ids, from which I can then load the entities.
I'd like to do that in one step, and I think I can do that with addEntity, but I am not sure how exactly. (Hibernate's documentation web site is down. Again.) I can use addEntity when all the columns for the entity table are present, but I have only the id now.
This complains about the missing columns:
return (List<MyEntity>) session.createSQLQuery(
"select entity_id from the_table where foreign_key_value = ?")
.addEntity("entity_id", MyEntity.class)
.setLong(0, foreignKey).list();

I think you want something like:
session.createSQLQuery("select {entity.*} from entity_table {entity} where ....")
.addEntity("entity", Entity.class).(bind-parameters).list();
Hibernate will expand "{entity.*}" to be the relevant columns from entity_table.
Although if you already have the IDs, you can simply use session.load() to convert those to actual instances (well, lazy-load proxies).

i would use a join
select *
from entity_table
where entity_id = (select entity_id
from non_hibernate_table
where id = ?)

For oracle dialect. If u have problem with mapping database column type to java data type u can set it manually like that: .addScalar("integerFieldName", Hibernate.INTEGER)
public class LookupCodeName
{
private String code;
private String name;
/*... getter-setters ... */
}
public class someBL {
public List<LookupCodeName> returnSomeEntity() {
SQLQuery sqlQuery = (SQLQuery)((HibernateSession)em).getHibernateSession()
.createSQLQuery( "SELECT st.name as name, st.code as code FROM someTable st")
.addScalar("code")
.addScalar("name")
.setResultTransformer(Transformers.aliasToBean(LookupCodeName.class));
}
return (List<LookupCodeName>)sqlQuery.list();
}

Related

JPQL Extract pk of an relation entity without a second query

I have these entities (is an example because i cant share real name entities):
#Entity
public class User { #Id private BigDecimal id; private String name, private Color favouriteColor }
#Entity
public class Color { #Id private Long colorId; private String colorName;}
In the table I have this data:
USER
ID|NAME|FavColor
1 |John| 1
2 |Sarah| 2
3 |Mike| 1
COLOR
1|Red
2|Blue
Now I want make a query that recover all my user data without select Color entity, only its ids.
#Query("new myDto(u.iduser,u.username,u.favcolor) from user u where favcolor in :listcolors")
This makes me an query of the two tables, I want a unique query because i dont need color entities, only the ids.
--
Other option that I am testing is making a implementation of a nativequery like this:
final List<MyDTO> result = new ArrayList<>();
Query q = entityManager.createNativeQuery("SELECT " +
" USER_ID, " +
" USER_NAME, " +
" FAV_COLOR " + +
"FROM USER " +
"WHERE FAV_COLOR IN (?)");
q.setParameter(1, colors.toString().replace("[","").replace("]",""));
Long TRUE = new Long(1L);
final List<Object[]> resultList = q.getResultList();
for (Object[] objects : resultList) {
MyDTOdto = new MyDTO();
dto.userId(((((BigDecimal) objects[0]) != null) ? ((BigDecimal) objects[0]).longValue() : null));
dto.userName(((((String) objects[0]) != null) ? ((String) objects[0]).longValue() : null));
dto.favColor(((((BigDecimal) objects[0]) != null) ? ((BigDecimal) objects[0]).longValue() : null));
result.add(dto);
}
return result;
In this case, I am getting error code (ORA-1722 - Number Not valid). I don't know what I can test now. Some ideas? Thanks
I am guessing you have issues with the SQL generated and your use of the inner join: when you call "u.favcolor" in the select clause, you are telling JPA to perform an inner join from User to Color based on the favcolor relationship. As favcolor is a Color reference, you are going to get the full color row, where as your native query implies you just want the foreign key value. If all you want is the fk/ID value from Color, the query should be:
"SELECT new myDto(u.iduser, u.username, color.id) FROM user u join u.favcolor color WHERE color.id in :listcolors"
This still might perform an inner join from user to color, but it should be in a single statement.
If you want to ensure you avoid the join:
Use EclipseLink's COLUMN JPQL extension to access the foreign key column directly. Something like:
"SELECT new myDto(u.iduser, u.username, COLUMN('FAV_COLOR', u) FROM user u WHERE COLUMN('FAV_COLOR', u) in :listcolors"
Use EclipseLink native query key functionality to access the "FAV_COLOR" foreign key column in the USER table directly for your JPQL queries. This requires a descriptor customizer to access, but allows you to use the foreign key value in JPQL queries directly without having to map it, and without the COLUMN mechanism tying your JPQL queries to a particular database table detail. This would allow a query of the form:
"SELECT new myDto(u.iduser, u.username, u.favColorVal FROM user u join u.favcolor color WHERE u.favColorVal in :listcolors"
Just map the FAV_COLOR as a basic mapping, in addition to the existing favColor reference mapping (or replacing it if you want):
#Basic
#Column(name="FAV_COLOR", updatable=false, insertable=false)
BigDecimal favColorId
This then allows you to use query "SELECT new myDto(u.iduser, u.username, u.favColorId FROM user u join u.favColorId color WHERE u.favColorId in :listcolors" to the same effect, but you can also just return the User instance (marking favColor as lazy and not serializable) as it will have the same data anyway.

I am new to springboot and need to insert json data in oracle table and avoid duplicate inserts

I am able to insert the json data in oracle table using intermediate table from springboot
I have a table abc-
ID first_name last_name cust_ID Active_Ind last_upd_dt
1 abc pqr 101 Y 01-Apr-2021
2 aaa bbb 102 Y 05-Feb-2021
I need to make sure-
If the new json data has the above existing value, do not update table abc, keep it as is and if it has new record only then insert. And if the oracle table record is not present in new json data, then change the ACTIVE_IND to 'N'
I tried the below query to insert value where not exists from intermediate table 'test':
insert into abc
(ID,
first_name,
last_name,
cust_ID,
active_ind,
last_upd_dt)
select
abc_seq.nextval,
first_name,
last_name,
cust_ID,
active_ind,
last_upd_dt
from test t
where not exists(
select null from abc a
where a.fist_name = t.first_name
and a.cust_ID = t.cust_ID);
This works fine in Oracle developer, but when I try the below query in springboot, it somehow inserts duplicates, not sure why it is happening, I have used prepared statement for the index.
insert into abc
(ID,
first_name,
last_name,
cust_ID,
active_ind,
last_upd_dt)
select
abc_seq.nextval,
?,
?,
?,
?,
?
from test t
where not exists(
select null from abc a
where a.fist_name = t.first_name
and a.cust_ID = t.cust_ID);```
I have tried merge queries as well, but none of them worked for me.
If you are using spring boot I'm assuming you have mapped entities and you are using JPA.
Once you mapped the entity
#Entity
#Table(name = "abc")
public class ABC {
#Id
private Long id;
#Column(name = "name")
private String name;
...
}
Then I also assume you created a Repository (if you are using the Repo pattern)
public interface ABCRepository extends JpaRepository<ABC, Long> {
//leave it blank If you don't need any particular method for querying
}
In this case you can use the findOne JPA method passing the Example of the object that you want the result to match. If it's just the ID then simply use the findByID. Anyways, you can now create yourself a saveIfExists(Example example)
public ABC saveIfNotExists(Example<ABC> example) {
return abcRepo.findOne(example).orElse(()-> {
return abcRepo.save(example);
};
}

JPA - Select All Rows from Dynamic Table Name

Hi guys I am new to jpa, named queries, etc.. and I need something like this:
select t from :tableName t
Later in code I want something like this:
em.createQuery(...);
setParameter("tableName", "Person")
Result would be:
select * from person
How to write such a generic jpa query statement allowing to select all rows from :tableName which may be defined at runtime? thanks in advance
Try this I think this works well
EntityManagerFactory emfactory=Persistence.createEntityManagerFactory("Eclipselink_JPA" );
EntityManager entitymanager = emfactory.createEntityManager();
Query query = entitymanager.
createQuery("Select p from Person p");
List<String> list = query.getResultList();
setParameter("foo", foo) is used to set the value for column of the table not to set the table name. I do not think it will work, as you want to set the table name dynamically.
You can try this:
public returnType foo(String tableName){
String jpql = "SELECT t FROM " + tableName+ " t";
Query query = em.createQuery(jpql);
//rest of the code
}

Hibernate native sql join query

I have a problem with hibernate native sql join query. My query is below and works on Mysql db.
SELECT c.cart_id, u.name, u.surname, c.totalPrice
FROM sandbox.cart c JOIN
sandbox.user u
ON u.id = c.placedBy
I am using hibernate in code and encountered an exception
java.sql.SQLException: Column 'id' not found.
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055)
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926)
com.mysql.jdbc.ResultSetImpl.findColumn(ResultSetImpl.java:1093)
Query in code here
Session session = hibernateUtil.getSessionFactory().getCurrentSession();
SQLQuery query = session.createSQLQuery(ORDER_PER_USER_QUERY);
query.addEntity(OrderPerUser.class);
return query.list();
Table column name
Cart
| cart_id | placedBy | totalPrice
User
| id | email | name | surname
My mapped class is
#Entity
public class OrderPerUser {
#Id
private long id;
private String name;
private String surName;
private long cartId;
private double totalPrice; }
You need to remove the line:
query.addEntity(OrderPerUser.class);
After that, you need to rewrite the code and map your object manually, because your OrderPerUser is not an entity:
Session session = hibernateUtil.getSessionFactory().getCurrentSession();
SQLQuery query = session.createSQLQuery(ORDER_PER_USER_QUERY);
List<OrderPerUser> returnList new ArrayList<>();
for(Object[] row : query.list()){
OrderPerUser orderPerUserObj = new OrderPerUser();
oderPerUserObj.setCartId(Long.parseLong(row[0].toString()));
//put other properties here
returnList.add(orderPerUserObj);
}
return returnList;
Edit1: Now I see that you added the mapped class, but OrderPerUser should not be an entity in your case, but a regular DTO. An entity requires an ID, but you can't select the ID in this case, because OrderPerUser is not part of a table, it is just some selected data that you want in your memory and not in the database. So you should make your OrderPerUser a regular data transfer object.
Please read about entities, data transfer objects, data access objects to see what each object should do.
My guess is that your OrderPerUser class which you try to use for collecting the result is expecting a column with name id, and you have no such column in your query...
Try using the query:
SELECT u.id, c.cart_id, u.name, u.surname, c.totalPrice
FROM sandbox.cart c
JOIN sandbox.user u ON u.id = c.placedBy

Ebean query using setDistinct() does not work

I'm using an ebean query in the play! framework to find a list of records based on a distinct column. It seems like a pretty simple query but the problem is the ebean method setDistinct(true) isn't actually setting the query to distinct.
My query is:
List<Song> allSongs = Song.find.select("artistName").setDistinct(true).findList();
In my results I get duplicate artist names.
From what I've seen I believe this is the correct syntax but I could be wrong. I'd appreciate any help. Thank you.
I just faced the same issue out of the blue and can not figure it out. As hfs said its been fixed in a later version but if you are stuck for a while you can use
findSet()
So in your example use
List<Song> allSongs = Song.find.select("artistName").setDistinct(true).findSet();
According to issue #158: Add support for using setDistinct (by excluding id property from generated sql) on the Ebean bug tracker, the problem is that an ID column is added to the beginning of the select query implicitly. That makes the distinct keyword act on the ID column, which will always be distinct.
This is supposed to be fixed in Ebean 4.1.2.
As an alternative you can use a native SQL query (SqlQuery).
The mechanism is described here:
https://ebean-orm.github.io/apidocs/com/avaje/ebean/SqlQuery.html
This is from the documentation:
public interface SqlQuery
extends Serializable
Query object for performing native SQL queries that return SqlRow's.
Firstly note that you can use your own sql queries with entity beans by using the SqlSelect annotation. This should be your first approach when wanting to use your own SQL queries.
If ORM Mapping is too tight and constraining for your problem then SqlQuery could be a good approach.
The returned SqlRow objects are similar to a LinkedHashMap with some type conversion support added.
// its typically a good idea to use a named query
// and put the sql in the orm.xml instead of in your code
String sql = "select id, name from customer where name like :name and status_code = :status";
SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
sqlQuery.setParameter("name", "Acme%");
sqlQuery.setParameter("status", "ACTIVE");
// execute the query returning a List of MapBean objects
List<SqlRow> list = sqlQuery.findList();
i have a solution for it:-
RawSql rawSql = RawSqlBuilder
.parse("SELECT distinct CASE WHEN PARENT_EQUIPMENT_NUMBER IS NULL THEN EQUIPMENT_NUMBER ELSE PARENT_EQUIPMENT_NUMBER END AS PARENT_EQUIPMENT_NUMBER " +
"FROM TOOLS_DETAILS").create();
Query<ToolsDetail> query = Ebean.find(ToolsDetail.class);
ExpressionList<ToolsDetail> expressionList = query.setRawSql(rawSql).where();//ToolsDetail.find.where();
if (StringUtils.isNotBlank(sortBy)) {
if (StringUtils.isNotBlank(sortMode) && sortMode.equals("descending")) {
expressionList.setOrderBy("LPAD("+sortBy+", 20) "+"desc");
//expressionList.orderBy().asc(sortBy);
}else if (StringUtils.isNotBlank(sortMode) && sortMode.equals("ascending")) {
expressionList.setOrderBy("LPAD("+sortBy+", 20) "+"asc");
// expressionList.orderBy().asc(sortBy);
} else {
expressionList.setOrderBy("LPAD("+sortBy+", 20) "+"desc");
}
}
if (StringUtils.isNotBlank(fullTextSearch)) {
fullTextSearch = fullTextSearch.replaceAll("\\*","%");
expressionList.disjunction()
.ilike("customerSerialNumber", fullTextSearch)
.ilike("organizationalReference", fullTextSearch)
.ilike("costCentre", fullTextSearch)
.ilike("inventoryKey", fullTextSearch)
.ilike("toolType", fullTextSearch);
}
//add filters for date range
String fromContractStartdate = Controller.request().getQueryString("fm_contract_start_date_from");
String toContractStartdate = Controller.request().getQueryString("fm_contract_start_date_to");
String fromContractEndtdate = Controller.request().getQueryString("fm_contract_end_date_from");
String toContractEnddate = Controller.request().getQueryString("fm_contract_end_date_to");
if(StringUtils.isNotBlank(fromContractStartdate) && StringUtils.isNotBlank(toContractStartdate))
{
Date fromSqlStartDate=new Date(AppUtils.convertStringToDate(fromContractStartdate).getTime());
Date toSqlStartDate=new Date(AppUtils.convertStringToDate(toContractStartdate).getTime());
expressionList.between("fmContractStartDate",fromSqlStartDate,toSqlStartDate);
}if(StringUtils.isNotBlank(fromContractEndtdate) && StringUtils.isNotBlank(toContractEnddate))
{
Date fromSqlEndDate=new Date(AppUtils.convertStringToDate(fromContractEndtdate).getTime());
Date toSqlEndDate=new Date(AppUtils.convertStringToDate(toContractEnddate).getTime());
expressionList.between("fmContractEndDate",fromSqlEndDate,toSqlEndDate);
}
PagedList pagedList = ToolsQueryFilter.getFilter().applyFilters(expressionList).findPagedList(pageNo-1, pageSize);
ToolsListCount toolsListCount = new ToolsListCount();
toolsListCount.setList(pagedList.getList());
toolsListCount.setCount(pagedList.getTotalRowCount());
return toolsListCount;

Categories