How to query an element inside an indexed collection using HQL? - java

Database data:
pkmn_id | pkmn_name
1 | Charmander
These are my entity:
Pokemon.Class
#Entity
#Table(name = "pkmn")
#Inheritance(strategy = InheritanceType.JOINED)
#NamedQuery(name = "#GET_POKEMON_BY_ID", query = "SELECT pkmn FROM Pokemon as pkmn FireType as ft WHERE pkmn.pkmnID = pkmn.fireAttributes[0]")
public abstract class Pokemon {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "pkmn_id")
private int pkmnID;
#Column(name = "pkmn_name")
private String pkmnName;
public long[] fireAttributes = { 1, 2, 3, 4, 5 };
FireType.class
#Entity
#Table(name = "pkmn_firetype")
#DynamicUpdate(value = true)
#SelectBeforeUpdate(value = true)
public class FireType extends Pokemon {
#Column(name = "fire_immunity")
private int fireImmunity;
#Column(name = "fire_attack")
private int fireAttack;
PokemonServlet.class
SessionFactory sessionFactory = new Configuration().configure("hibernate.cfg.xml").buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
Query query2 = session.getNamedQuery("#GET_POKEMON_BY_ID");
FireType pk2 = (FireType) query2.uniqueResult();
System.out.println(pk2.getFireAttack());
session.getTransaction().commit();
session.close();
I have an error in my NamedQuery, the problem is on how I used the array index in the WHERE clause. I'm confused with the right way of including an indexed collection in the WHERE clause.
What is the correct way of implementing this query, wherein the pkmn_id must match the value in the index of an array to retrieve the correct object?
This is my reference
JBoss Hibernate Documentation

You forgot to put comma only. Your query should be as below and use in when you are comparing id with more than one.
SELECT pkmn FROM Pokemon as pkmn , FireType as ft WHERE pkmn.pkmnID in pkmn.fireAttributes[0]

Related

different result by executing query in console and namedQuery

in my java web application i need to inquire a list of deposits from a view named VwDepositsInfo by customerNumber.
when i execute my query:
select * from VW_DEPOSIT_INFO v where v.CUSTOMER_NUMBER=:customerNo
in database console my resultList size is 2 and have something like this:
1-{depositTypeDesc="shortTerm"} {depositTypeCode="850"}
2-{depositTypeDesc="longTerm"} {depositTypeCode="2"}
but when i test my code that includes a namedQuery:
#NamedQuery(
name = "inquireAccountByCustomerNumber",
query = "select c from VWDepositInfo c where c.customerNumber=:customerNo"
)
i get a resultList with size 2 but both the same, sth like this:
1-{depositTypeDesc="shortTerm"} {depositTypeCode="850"}
2-{depositTypeDesc="shortTerm"} {depositTypeCode="850"}
when i make it nativeQuery with defining the result class:
Query query = entityManager.createNativeQuery("select * from VW_DEPOSIT_INFO v where v.CUSTOMER_NUMBER=:customerNo", VWDepositInfo.class);
again i get the wrong results.
finally i tried nativeQuery without defining the result class:
Query query = entityManager.createNativeQuery("select * from VW_DEPOSIT_INFO v where v.CUSTOMER_NUMBER=:customerNo");
and result was as i expected to be.
and this is my VwDepositsInfo.class:
#Entity
#Table(name = "VW_DEPOSIT_INFO")
#Audited(withModifiedFlag = false)
#NamedQueries(
{#NamedQuery(
name = "inquireAccountByCustomerNumber",
query = "select c from VWDepositInfo c where c.customerNumber=:customerNo"
)
}
)
public class VWDepositInfo implements Serializable {
#Id
#Column(name = "CUSTOMER_NUMBER")
private Long customerNumber;
#Column(name = "BRANCH_CODE")
private Long branchCode;
#Column(name = "DEPOSIT_TYPE_CODE")
private Long depositTypeCode;
#Column(name = "DEPOSIT_SERIAL")
private Long depositSerial;
#Column(name = "DEPOSIT_TYPE_DESC")
private String depositTypeDesc;
#Column(name = "CURRENCY_TYPE_DESC")
private String currencyTypeDesc;
#Column(name = "DEPOSIT_OPEN_DATE")
private Date depositOpenDate;
Does anyone know why this is happening???
VW = view?
You probably need to specify the master key
use #id for unique field :)
you probably need more than one field with #id for a unique row.
for example both of DEPOSIT_TYPE_CODE and customerNumber

ClassCastException with hibernate

I am trying to fetch specific fields from my entities. I need the result in my entity structure.
Following are my entities:
Country
public class CountryModel {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "CmtID")
private int id;
#Column(name = "CmtName")
private String name;
#JoinColumn(name="CmtStateID")
#OneToMany(targetEntity=StateModel.class,fetch=FetchType.EAGER)
private List<StateModel> state;
}
State
public class StateModel {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "SmtID")
private int id;
#Column(name = "SmtName")
private String name;
}
Following is the HQL query am executing:
Query query = session.createQuery("select c.name, s.name from CountryModel c join c.state s where c.id=2");
CountryModel stateModel = (CountryModel) query.uniqueResult();
But am getting the following error:
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to com.muziris.entity.CountryModel
Thanks for helping.
Expected result:
Country :
name : india
state :
name : kerala
name : goa
name : Pak
state :
name : karachi
Since your classes are mapped you can try:
Query query = session.createQuery("from CountryModel c where c.id=2");
CountryModel countryModel = (CountryModel) query.uniqueResult();
Let's make use of the mapping and HQL.
From there you can use a DTO to have only the data that you need
public CountryDTO transform(CountryModel cm){
String countryName = cm.getName();
List<String> stateNames = cm.getState().stream.map(StateModel::getName)
.collect(Collectors.toList());
return new CountryDTO(countryName, stateNames);
}
CountryDTO is the result that you need.
Hibernate returns List<Object[]> when you use the projections.
List<Object[]> is a list of specified projection columns.
Some links
https://stackoverflow.com/a/36883968/3405171
How to transform a flat result set using Hibernate

how to use NOT LIKE in HQL?

I have a entity as below
public class Employee implements Serializable {
#Id
#Column(name = "EMPSEQ")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long empSeq;
#Column(name = "EMPID")
private String empId;
#Column(name = "WINDOWSLOGINID")
private String logInId;
// assume respective getter and setter methods
}
I want to query all row where logInId does not start with "5"
I tried below code:
query = session.createQuery("select * from Employee e where e.logInId not like 5%");
the above code didn't work. what is the right way to use NOT LIKE in HQL
In your query there's an error:
query = session.createQuery("select * from Employee e where e.logInId not like 5%");
become:
query = session.createQuery("select * from Employee e where e.logInId not like '5%'");
e.logInId is string, so you must quote your condition 5%.
You can also use Hibernate Criteria for the same.
JPA EntityManger has unwrap() method which will return session.
Session session = getEntityManager().unwrap(Session.class);
Criteria criteria = session.createCriteria(Pojo.class);
criteria.add(Restrictions.not(Restrictions.like("loginId","5%")));
List<Pojo> list=criteria.list();
if(null!=list && list.size()> 0){
return list.get(0);
}
return null;

JPA2:i persist a entity ,there is no exception but the data is not saved in database

I am using EJB to write a CRUD demo code on netbeans..when i write a code that can save data into database ,there is no error and exception but the data is not saved in database
code:
entitybean:
#Entity
#Table(name = "book_book")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "BookBook.findAll", query = "SELECT b FROM BookBook b"),
#NamedQuery(name = "BookBook.findByIsbn", query = "SELECT b FROM BookBook b WHERE b.isbn = :isbn"),
#NamedQuery(name = "BookBook.findByDealTotal", query = "SELECT b FROM BookBook b WHERE b.dealTotal = :dealTotal"),
#NamedQuery(name = "BookBook.findBySaleTotal", query = "SELECT b FROM BookBook b WHERE b.saleTotal = :saleTotal"),
#NamedQuery(name = "BookBook.findBySalePrice", query = "SELECT b FROM BookBook b WHERE b.salePrice = :salePrice"),
#NamedQuery(name = "BookBook.findByDealPrice", query = "SELECT b FROM BookBook b WHERE b.dealPrice = :dealPrice")})
public class BookBook implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
// #NotNull
#Column(name = "isbn")
private Long isbn;
#Column(name = "deal_total")
private Integer dealTotal;
#Column(name = "sale_total")
private Integer saleTotal;
#Column(name = "sale_price")
private Integer salePrice;
#Column(name = "deal_price")
private Integer dealPrice;
#OneToMany(mappedBy = "isbn")
private List<BookBookdetail> bookBookdetailList;
DAClass(not a sessionbean):
EntityManagerFactory factory=Persistence.createEntityManagerFactory("BookXPU");
EntityManager em=factory.createEntityManager();
public long createBook(Long isbn, Integer dealTotal, Integer saleTotal, Integer salePrice, Integer dealPrice){
BookBook book=new BookBook();
book.setDealTotal(dealTotal);
book.setSalePrice(salePrice);
book.setDealTotal(dealTotal);
book.setDealPrice(dealPrice);
book.setIsbn(isbn);
List<BookBookdetail> list=new ArrayList<BookBookdetail>();
book.setBookBookdetailList(null);
em.persist(book);
Query query =em.createQuery("SELECT b FROM BookBook b WHERE b.isbn = :isbn");
query.setParameter("isbn",book);
List list1=query.getResultList();
for (Iterator it = list1.iterator(); it.hasNext();) {
BookBookDetail book1 = (BookBookDetail)it.next();
list.add(book1);
}
book.setBookBookdetailList(list);
em.merge(book);
return book.getIsbn();
}
Thanks...
Your entities are not persisted because you're not flushing the entities to your database.
If you use your code in a Java SE than you should do:
EntityTransaction tx = em.getTransaction();
tx.begin();
// persist, merge, etc. - operations which needs to be in the Tx...
tx.close();
Without it, you're not giving a sign that the data you've changed should be flushed to the underlying database.
When you've moved your code into an EJB you were using a JTA transactions (implicitly). Therefore, an EntityManager's transaction was a part of the JTA transaction. By default every method of an EJB is a single JTA transaction.
Now, combining these pieces of information it occurs that by marking your class as an EJB you've flushed the data to the underlying database.
HTH.

how to write JPA query

Learning how to write JPA query. Please advise me whether it possible to write the below queries more efficiently, may be in a single select statement. May be a join, but not sure how to do it.
class Relationship {
#ManyToOne
public String relationshipType; //can be MANAGER, CUSTOMER etc
#ManyToOne
public Party partyFrom; // a person who has a relation
#ManyToOne
public Party partyTo; // a group a person relate to
}
Queries:
String sql = "";
sql = "select rel.partyTo";
sql += " from Relationship rel";
sql += " where rel.partyFrom = :partyFrom";
sql += " and rel.relationshipType= :typeName";
Query query = Organization.em().createQuery(sql);
query.setParameter("partyFrom", mgr1);
query.setParameter("typeName", "MANAGER");
List<Party> orgList = query.getResultList();
String sql2 = "";
sql2 = "select rel.partyFrom";
sql2 += " from Relationship rel";
sql2 += " where rel.partyTo = :partyToList";
sql2 += " and rel.relationshipType = :typeName2";
Query query2 = Organization.em().createQuery(sql2);
query2.setParameter("partyToList", orgList);
query2.setParameter("typeName2", "CUSTOMER");
List<Party> personList2 = query2.getResultList();
Both the queries work. Query 1 returns a list of groups, where the person (mgr1) has a relation MANAGER with. Query 2 returns all the Persons they are CUSTOMER to the groups returned by query 1. In effect, I get a list of Person they are belong to (customer) the same group where the Person (mgr1) has a relation MANAGER with.
Is it possible to combine them into single sql statement so possibly only one db access?
You literally nest one query inside the other, and use a "where in" clause to specify that the outer query should fetch customers from the inner query.
select rel2.partyFrom
from Relationship rel2
where rel2.relationshipType = :typeName2 /* customer */
and rel2.partyTo.id in
(select rel.partyTo.id
from Relationship rel
where rel.partyFrom = :partyFrom
and rel.relationshipType = :typeName)
Your calling code passes typeName, typeName2, and partyFrom parameters as before. PartyTo parameter is not needed, since the data comes from the subselect (inner query.)
You can achieve the same thing using a self join, with a where clause that filters managers on the left side, and customers on the right side, but using an 'in' clause is semantically clearer.
EDIT: I addded .id to the subselect, which I think is needed.
This is not answer to question but helping other folks in case if someone looking into #OneToMany relation in Spring Data JPA using JPQL, because the question is related to JPA so thought to share my 2-cents, apologize in advance
#Entity
#Table(name = "MY_CAR")
public class MyCar {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "DESCRIPTION")
private String description;
#Column(name = "MY_CAR_NUMBER")
private String myCarNumber;
#Column(name = "RELEASE_DATE")
private Date releaseDate;
#OneToMany(cascade = { CascadeType.ALL })
#JoinTable(name = "MY_CAR_VEHICLE_SERIES", joinColumns = #JoinColumn(name = "MY_CAR_ID "), inverseJoinColumns = #JoinColumn(name = "VEHICLE_SERIES_ID"))
private Set<VehicleSeries> vehicleSeries;
public MyCar() {
super();
vehicleSeries = new HashSet<VehicleSeries>();
}
// set and get method goes here
#Entity
#Table(name = "VEHICLE_SERIES ")
public class VehicleSeries {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "SERIES_NUMBER")
private String seriesNumber;
#OneToMany(cascade = { CascadeType.ALL })
#JoinTable(name = "VEHICLE_SERIES_BODY_TYPE", joinColumns = #JoinColumn(name = "VEHICLE_SERIES_ID"), inverseJoinColumns = #JoinColumn(name = "BODY_TYPE_ID"))
private Set<BodyType> bodyTypes;
public VehicleSeries() {
super();
bodyTypes = new HashSet<BodyType>();
}
// set and get method goes here
#Entity
#Table(name = "BODY_TYPE ")
public class BodyType implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "NAME")
private String name;
// set and get method goes here
public interface MyCarRepository extends JpaRepository<MyCar, Long> {
public Set<MyCar> findAllByOrderByIdAsc();
#Query(value = "select distinct myCar from MyCar myCar "
+ "join myCar.vehicleSeries as vs join vs.bodyTypes as bt where vs.seriesNumber like %:searchMyCar% "
+ "or lower(bt.name) like lower(:searchMyCar) or myCar.bulletinId like %:searchMyCar% "
+ "or lower(myCar.description) like lower(:searchMyCar) "
+ "or myCar.bulletinNumber like %:searchMyCar% order by myCar.id asc")
public Set<MyCar> searchByMyCar(#Param("searchMyCar") String searchMyCar);
}
Some data in tables like
Select * from Vehicle_Series
ID SERIES_NUMBER
1 Yaris
2 Corolla
Select * from Body_Type
ID NAME
1 Compact
2 Convertible
3 Sedan

Categories