Hibernate createNativeQuery returns duplicate rows - sql

I have 2 database tables Customer and Items with 1 -> many relation. To fetch data from database i am using the following query.
select customer.id, customer.name, items.itemName, items.itemPrice from testdb.customer INNER JOIN items ON items.customer_Id = customer.id
I have an entity class Customers
#Entity
public class Customer{
#Id
private int id;
#Column
private String name;
#Column
private String itemName;
#Column
private int itemPrice;
public Customer() {}
//Getter and setter are here
.......
}
in Service class i have the following code.
#GET #Path("/getCustomerInfo")
#Produces(MediaType.APPLICATION_JSON)
public List getCustomerInfo() {
CustomerDao dao = new CustomerDao();
return dao.getBuildingsCustomerInfo();
}
in my DAO class i have the following code
public List<Customer> getCustomerInfo(){
Session session = SessionUtil.getSession();
String queryString = "the above mentioned query";
List<Customer> customerInfo = session.createNativeQuery(queryString, Customer.class) ;
session.close();
return customerInfo;
}
I am getting the following JSON response from the service
[id:1, name:"Alfred", itemName:"jeans", itemprice:10],[id:1, name:"Alfred", itemName:"jeans", itemprice:10],[id:2, name:"James", itemName:"watch", itemPrice:20 ],[id:2, name:"James", itemName:"watch", itemPrice:20 ], [id:2, name:"James", itemName:"watch", itemPrice:20 ]
The number of results are 5 which is correct But 2nd result is a copy of 1st, 4th and 5th are copies of 3rd. In 2nd, 4th and 5th results the itemName and the itemPrice should be different.
if I use createSQLQuery(queryString); instead of createNativeQuery(queryString, Customer.class); I am getting the correct result but without entity attribut names.
[1, "Alfred", "jeans", 10],[1, "Alfred", "shirt", 15],[2, "James", "watch", 20], [2, "James", "coffee", 25], [2, "James", "drinks", 30]
I have seen number of articles but could not find the solution. I have to use createNativeQuery() not createSQLQuery() because I need to map the entity class attributes. Please let me know if i am doing something wrong.

Your data structure is wrong on the Java side and not corresponding to the database relation. In the relation you describe you need to have a list of items:
#Entity
public class Customer implements Serializable {
// ... the fields you have so far
// assuming the parent field on the other side is called customer
// you may also want to set the cascade and orphanRemoval properties of the annotation
#OneToMany(mappedBy = "customer")
#JsonManagedReference // assuming you're using Jackson databind JSON
private List<Item> items;
}
And on the Item side:
#Entity
public class Item implements Serializable {
#Id
private int id;
#JsonBackReference
#ManyToOne
#JoinColumn(name = "customer_Id")
private Customer customer;
}
Then if you really the JSON data strucutred that way, you need a third Entity class to use as a ResultSetMapping.
#Entity
#SqlResultSetMapping(
name = "CustomerItem",
entities = #EntityResult(entityClass = CustomerItem.class)
)
#NamedNativeQueries({
#NamedNativeQuery(
name = "CustomerItem.getAll",
resultSetMapping = "CustomerItem"
query = "select customer.id as cid, items.id as iid, customer.name,"
+ " items.itemName, items.itemPrice from testdb.customer INNER JOIN"
+ " items ON items.customer_Id = customer.id"
)
})
public class CustomerItem implements Serializable {
#Id
private int cid;
#Id
private int iid;
#Column
private String name;
#Column
private String itemName;
#Column
private int itemPrice;
... getters and setters
}
Then you can use the native query in named variant, which should offer some slight optimizations.
List<CustomerItem> lst = em.createNamedQuery("CustomerItem.getAll", CustomerItem.class)
.getResultList();
The use of #SqlResultSetMapping is so that the returned entities are not monitored for changes, but you can still use the defined entity for the result. I believe that by JPA specification it should also work without it, but in Hibernate it doesn't. Could be a bug, or a planned, but not implemented feature, or I could just be misinterpreting the JPA usage, but this workaround does work with Hibernate 5+.

Not sure about the exact reason behind duplicates but SELECT DISTINCT will solve your issue as it will take only distinct records.
Refer using-distinct-in-jpa

I solve this issue by using #SqlResultSetMapping

Related

Subquery - JPA - Include Subquery as part of the main selection

I have an issue to add the result of a subquery as part of the selection.
This is how my data model looks like:
#Entity
#Table(name = "flow")
public class Flow {
#Id
Long id;
#OneToMany(mappedBy="flow", fetch = FetchType.LAZY)
Set<Subscription> subscribers;
... other internal fields
//extra fields that come from other tables
#Transient //as it is not part of the model sometimes must be null
Long numberOfActiveSubscribers;
}
#Entity
#Table(name = "subscriptions")
public class Subscription {
#Id
Long id;
#ManyToOne
#JoinColumn(name = "idflow")
Flow flow;
#OneToMany(name = "user")
User user;
#Column(name = "active")
boolean active;
}
I need to implement a query using jpa specifications that will include in its definition the number of user that have active subscriptions to the flow. So that I will be able to use pagination over that, including sort by this field that is not part of the original flow table. The SQL query I came out with look like this:
SELECT f.*,
(SELECT count(sf.id)
FROM subscription sf
WHERE sf.active = true
AND sf.idf = f.id) as numberofactivesubscribers,
FROM flow f;
I would like to us it in a findAll method like so:
this.repository.findAll(new Specification<Flow>() {
#Override
public Predicate toPredicate(Root<Flow> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
Subquery<Long> sq = query.subquery(Long.class);
Root<Subscription> subsRoot = sq.from(Subscription.class);
sq.select(cb.count(subsRoot.get("id")))
.where(cb.equal(subsRoot.get("flow"), flowRoot),
cb.equal(subsRoot.get("active"), true));
//I DONT KNOW HOW TO INCLUDE THIS AS A PART OF THE MAIN SELECT OF THIS QUERY
}
}, pagination);
But as you can see I don't know how to include the subquery as part of the select method as I did in my SQL query.

Spring Data JPA Query for inner join table throwing error

Spring DATA JPA question... I am trying to write a query to access the data in my sql join table.
I have my join table set up as follows:
#Entity
#Table(name="WritingCompany")
public class WritingCompany {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "companyId")
private Long id;
// private String companyName;
#ManyToMany
#JoinTable(name = "Join-WritingCo-Carrier",
joinColumns = #JoinColumn(name="writingCo"),
inverseJoinColumns = #JoinColumn(name="carrier")
)
private Set<CarrierAppointment> carriers;
//...getters and setters
}
public class CarrierAppointment {
// ...
#ManyToMany(
cascade=CascadeType.ALL,
mappedBy = "companyName"
)
private Set<WritingCompany> companies;
public Set<WritingCompany> getCompanies() {
return companies;
}
public void setCompanies(Set<WritingCompany> companies) {
this.companies = companies;
}
//...
}
I am unsure which class repository I need to write the query for... I am trying to find all the writingCo names from the join table that all have the same carrier id that matches one specific carrier.
The Join Table is set up through writing company but I feel like it should be accessed through CarrierAppointment Repository since I am matching carrier Id's.
This is what I've tried in the CarrierAppointmentrepository and it throws this error (unexpected token: Join near line 1, column 94):
#Query("Select companyName FROM WritingCompany INNER JOIN CarrierAppointment ON Join-WritingCo-Carrier.carrier= CarrierAppointment.CarrierAppointmentId")
List<CarrierAppointment> findCarrierAppoinmentFromJoin(CarrierAppointment carrier);
I've also tried:
#Query("SELECT writingCo FROM Join-WritingCo-Carrier WHERE carrier= CarrierAppointment.CarrierAppointmentId")
List<CarrierAppointment> findCarrierAppoinmentFromJoin(CarrierAppointment carrier);
Then I tried this in the writingCompanyRepository which also throws a similar error:
#Query("Select companyName FROM WritingCompany INNER JOIN CarrierAppointment ON Join-WritingCo-Carrier.carrier= CarrierAppointment.CarrierAppointmentId")
List<WritingCompany> findAllWithDescriptionQuery(CarrierAppointment carrier);
I am having a hard time understanding what this query is saying. Do I ever need to access the columns from the sql join table, or am I just querying around the join table by asking for each class that is making up the join columns in the join table? What is the right part of the statement, after INNER JOIN stating ? Could someone please provide a deeper explanation of why the query is written so I can figure out why it's not working? I've been reading a lot of inner join examples and just can't seem to figure it out.

Breeze Query: compare two columns on Related entity

Using Breeze, how can I compare two columns on a related property of an entity?
public class TableA{
public ICollection<TableB> TableBEntity {get; set;}
}
public class TableB{
public TableC TableCEntity {get; set;}
}
public class TableC {
public string columnA { get; set;}
public string columnB { get; set;}
}
var subpredicate = Predicate.create('TableCEntity.columnA', FilterQueryOp.Equals, 'TableCEntity.columnB');
var predicate = Predicate.create('TableBEntity', FilterQueryOp.Any, subpredicate);
var query1 = EntityQuery.from('TableB')
.where(subpredicate);
var query2 = EntityQuery.from('TableA')
.where(predicate );
query1 above executes without error. However query2 gives me the error:
The query specified in the URI is not valid. Could not find a property named 'TableCEntity' on type 'TableA'.
It seems as the subpredicate is not properly evaluated and it searches for the property TableCEntity on TableA instead of on TableB. If I change the subpredicate to
var subpredicate = Predicate.create('TableCEntity.columnA', FilterQueryOp.Equals, 'asamplevalue');
then, query2 works find. It just does not work the right side of the predicate is a record's column.
Am i doing something wrong or is this a bug?
The breeze 'any' and 'all' operators require that the property returned by the first expression ( "orders" in the example below) be a nonscalar navigation property. i.e. a navigation property that returns a collection. The subpredicate is then is just a simple predicate against the type returned by the first expression.
var query = EntityQuery.from("Employees")
.where("orders", "any", "freight", ">", 950);
with predicates this would be expressed as follows
var p2 = Predicate.create("freight", ">", 950);
var p1 = Predicate.create("orders", "any", p2);
var query = EntityQuery.from("Employees").where(p1);
In your case, i'm not sure what you are trying to do with your 'query2'. 'query2' appears to be a query over a collection of 'TableB' entities returned from 'TableA', but the 'subpredicate' deals with 'TableC' entities.
If this doesn't help, it might be easier to assist if you could restate your TableA, B and C names with table names that are a bit more intuitive and pluralize the collection property names.
Hope this helps.

ERROR: subquery in FROM must have an alias

I am struggling with this problem :
Caused by: org.postgresql.util.PSQLException: ERROR: subquery in FROM
must have an alias IndiceĀ : For example, FROM (SELECT ...) [AS] foo.
PositionĀ : 15
The query looks like this :
Query query = em.createQuery("select u from UserClass as u where u.id.id = :id")
The only tricky thing here I found here is the u.id.id, the UserClass class is using en EmbeddedId :
#Entity
#Table(name = "TABLE_USER")
public class UserClass implements {
#EmbeddedId
private UserClassPK id;
...
}
And here is the UserClassPK class :
#Embeddable
public class UserClassPK {
#Column(name = "ID_UTILISATEUR")
private String id;
}
Aside from that, I have no idea why this error is occuring.
Edit : Added the MyClassPK class. Also it was a bad choice from picking "User" as entity name for the example, I changed it to UserClass.
Just found the solution ! The problem came from the interpretation of query.getSingleResult() which generated a subquery.
I just had to change the dialect used by JPA, in src/main/resources/spring-jpa.xml :
<context:property-placeholder
location="classpath*:jpa-postgresql.properties"
ignore-unresolvable="true" />
With the jpa-postgresql.properties file :
hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
jpa.dialect=org.springframework.orm.jpa.vendor.HibernateJpaDialect
jpa.vendor.adapter=HibernateJpaVendorAdapter

Get record from another table using JPA

I have been trying to figure out how to do this for sometime without any luck and have not managed to find anything useful while search on Google either.
I have THREE tables:
HOTEL
- id
- name
- local_id (foreign key)
DESCRIPTION
- id
- description
- hotel_id (foreign key)
- locale_id (foreign key)
LOCALE
- id
- local
I also have the following HOTEL DAO model:
#Entity
#Table(name = "HOTEL")
public class Hotel implements Serializable {
#Column(name = "id")
private long id;
#Column(name = "description")
private HotelDescription description;
}
Using JPA, how can I retrieve the data from table DESCRIPTION based on hotel_id and locale_id to populate description in DAO model hotel?
Well, you also have HotelDescription JPA entity, right? So you can define bidirectional mapping for entities.
instead of
#Column(name = "description")
private HotelDescription description;
you should have something like
#OneToOne(mappedBy = "hotel", cascade = CascadeType.ALL)
private HotelDescription desc;
and on the other side, in HotelDescription you should have back mapping
#OneToOne
#JoinColumn(name = "hotel_id")
private Hotel hotel;
When you will extract Hotel entity, JPA will also fetch child entity (HotelDescription) for you.
if you want to use #OneToMany mapping it will be (many descriptions for one hotel)
#OneToMany(mappedBy = "hotel", cascade = CascadeType.ALL)
private HotelDescription desc;
and on the other side
#ManyToOne
#JoinColumn(name = "hotel_id")
private Hotel hotel;
In JPA you can use several types of mapping like OneToMany, ManyToMany... That's only basics. Find a tutorial. You may start here: http://docs.oracle.com/javaee/6/tutorial/doc/bnbqa.html (not the best one probably)
Oh. And make sure you annotate id with #Id
I would consider ditching the Locale table and working with java.util.Locale directly. Hibernate (not sure about other JPA implementations) has auto type conversion from char column to java.util.Locale. This would then look something like:
DESCRIPTION
- id
- description
- hotel_id (foreign key)
- locale
And Entity:
import java.util.Locale;
#Entity
#Table(name = "HOTEL")
public class Hotel implements Serializable {
#Column(name = "id")
private long id;
#OneToMany
#JoinColumn(name = "holiday_id", nullable = false)
#MapKeyColumn(name = "locale_id")
private Map<Locale, HotelDescription> descriptions;
public String getDescriptionForLocale(Locale locale){
//try an exact match e.g. en_us
if(descriptions.containsKey(locale){
return descriptions.get(locale).getDescription();
}
//try language only e.g. en
else if (decsriptions.containsKey(locale.getLanguage){
return descriptions.get(locale.getlanguage()).getDescription();
}
//return a default or null
return ??
}
}