Hibernate - Group two entities - java

I have this code:
Map<OrderProduct, Product> temp =
session.createQuery("FROM OrderProduct " +
"WHERE orderId = '" + orderId + "'", OrderProduct.class)
.getResultList()
.stream()
.collect(Collectors.toMap(
k -> k,
v -> session.createQuery("FROM Product " +
"WHERE id = '" + v.getProductId() + "'", Product.class)
.getSingleResult()));
Here I take all order products of an specific order(orderId).
After make a stream and collect it as Map.
On key put order products and for value make another query to get product(product info).
Now I do 2 queries for every order product. There is a way to make all of this with just a single query?
Something like this:
SELECT *
FROM order_products OP, products P
WHERE OP.product_id = P.id;
But I don't know how to use in hibernate.
Here are entities:
#Entity
#Table(name = "order_products")
public class OrderProduct{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "order_id")
private Integer orderId;
#Column(name = "product_id")
private Integer productId;
#Column(name = "quantity")
private Integer quantity;
//getters setters
}
#Entity
#Table(name = "products")
public class Product{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
Integer id;
#Column(name = "name")
String name;
//getters setters
}
Here is a short example of how db look:
OrderProduct:
id-----order_id-----product_id-----quantity
1------1------------1--------------2
2------1------------2--------------1
3------2------------1--------------1
Product:
id-----name
1------productOne
2------productTwo

For many to one relation :
Change your entity to this :
#Entity
#Table(name = "products")
public class Product{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
Integer id;
#Column(name = "name")
String name;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "product", cascade = { CascadeType.ALL })
private List<OrderProduct> orderProducts = new ArrayList<OrderProduct>();
//getters setters
}
#Entity
#Table(name = "order_products")
public class OrderProduct{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
#JoinColumn(name = "product_id")
private Product product;
#Column(name = "quantity")
private Integer quantity;
//getters setters
}
Now the code :
int orderId = 1; // put any id
OrderProduct orderProduct = session.get(OrderProduct.class, orderId);
System.out.println(orderProduct.getProduct().getId());
Hope this helps you. :)

Related

Reading nested collection QueryDSL

I am using queryDSL to fetch the inner collection of data and failed to do so. My entities are
#Entity
#Table(name = "countries")
#Setter
#Getter
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long countryId;
#Column(name = "name")
private String name;
#Column(name = "data")
private String data;
#OneToOne(mappedBy = "country")
private State stateJoin;
}
#Entity
#Table(name = "states")
#Setter
#Getter
public class State {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long stateId;
#Column(name = "name")
private String name;
#Column(name = "count")
private String count;
#Column(name = "co_id")
private Long countryId;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "co_id", referencedColumnName = "id", updatable = false, insertable = false)
private Country country;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "state_id", referencedColumnName = "id")
private Set<Town> towns;
}
#Entity
#Table(name = "towns")
#Setter
#Getter
public class Town {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "town_id")
private Long townId;
#Column(name = "name")
private String name;
#Column(name = "people_count")
private String peopleCount;
#Column(name = "st_id")
private Long stateId;
}
and in querydsl i am trying below query and always failing to retrieve inner collection towns
List<Expression> childGroup = new ArrayList<>();
query.from(countries);
childGroup.addAll(Arrays.asList(countries.name, countries.data, countries.stateJoin));
query.join(countries.stateJoin, State);
childGroup.add(Projections.bean(State.class, name, count, town)
.as((Path) countries.stateJoin));
OR
childGroup.add(Projections.bean(State.class, name, count, list(town)).as((Path) countries.stateJoin));
query.select(fields);
query.where();
final Map<? extends Number, ? extends Object> t =
(Map<? extends Number, ? extends Object>)
query
.limit(pageRequest.getPageSize())
.offset(pageRequest.getOffset())
.distinct()
.transform(
GroupBy.groupBy(groupByPath)
.as(Projections.bean(Countris.class, childGroup.toArray(new Expression[0]))));
while executing the above line exactly i am getting always SQLSyntax error as i see the underlying SQL is with
. as towns
Can some one help me how to read the nested collection formed by JPA join?

Hibernate: N+1 fix for #OneToOne

I have #OneToOne relationship with classes:
#Entity
#Table(name = "persons", schema = "persons_info")
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "first_name",
nullable = false)
#JsonProperty("first_name")
private String firstName;
#Column(name = "last_name",
nullable = false)
#JsonProperty("last_name")
private String lastName;
#Basic
#Column(name = "birth_date", nullable = false)
private Date birthDate;
#OneToOne(cascade = CascadeType.ALL,
orphanRemoval = true)
#JoinColumn(name = "address_id",
referencedColumnName = "id")
private Address address;
// setters, getters, equals...
}
Address:
#Entity
#Table(name = "addresses", schema = "persons_info")
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false)
private String city;
#Column(nullable = false)
private String street;
#Column(nullable = false)
private String house;
#Column(nullable = false)
private String flat;
#JsonIgnore
#OneToOne(mappedBy = "address")
private Person person;
// setters, getters, equals...
}
I have a default JpaRepository for person:
#Repository
public interface PersonRepository
extends JpaRepository<Person, Long> {
}
And when i calling repository.findAll() i taking n+1 problem:
Hibernate:
select
a1_0.id,
a1_0.city,
a1_0.flat,
a1_0.house,
p1_0.id,
p1_0.birth_date,
p1_0.first_name,
p1_0.last_name,
a1_0.street
from
persons_info.addresses a1_0
left join
persons_info.persons p1_0
on a1_0.id=p1_0.address_id
where
a1_0.id=?
Hibernate:
select
a1_0.id,
a1_0.city,
a1_0.flat,
a1_0.house,
p1_0.id,
p1_0.birth_date,
p1_0.first_name,
p1_0.last_name,
a1_0.street
from
persons_info.addresses a1_0
left join
persons_info.persons p1_0
on a1_0.id=p1_0.address_id
where
a1_0.id=?
How i can fix that? (I want fetching with JOIN like this example: SELECT * FROM persons INNER JOIN address ON person.address_id = address.id)
Solved by adding #Query annotation:
#Repository
public interface PersonRepository
extends JpaRepository<Person, Long> {
#Query("""
SELECT p FROM Person p
LEFT JOIN FETCH p.address a""")
public List<Person> findAll();
}
Now that's looks like:
Hibernate:
select
p1_0.id,
a1_0.id,
a1_0.city,
a1_0.flat,
a1_0.house,
a1_0.street,
p1_0.birth_date,
p1_0.first_name,
p1_0.last_name
from
persons_info.persons p1_0
left join
persons_info.addresses a1_0

JPA : How to handle mapping with a table that has relationship with two other tables?

I have three tables, table A (product), table B (invoice) and table C (invoices_info) which contains two columns referencing invoice_id and product_id. How can i insert a new entry (a new invoice) while inserting the products to the appropriate table and inserting the invoice info to its table also ?
Here are the entity classes :
Product
#Entity
#Table(name = "product")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "family_id")
private long familyId;
#Column(name = "product_name")
private String productName;
#Column(name = "product_category")
private String productCategory;
#Column(name = "product_quantity")
private int productQuantity;
//getters and setters
}
Invoice
#Entity
#Table(name = "invoice")
public class Invoice {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "invoice_id")
private Long id;
#Column(name = "provider_id")
private Long providerId;
#Column(name = "total")
private int invoiceTotal;
#Column(name = "date")
private Date invoiceDate;
//getters and setters
}
InvoiceInfo
#Entity
#Table(name = "invoice_info")
public class InvoiceInfo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "item_id")
private long id;
#Column(name = "product_id")
private long productId;
#Column(name = "invoice_id")
private long invoiceId;
//getters and setters
}
InvoiceInfo should be join table, Define relationship on entities Product & Invoice using annotations #OneToMany, #ManyToOne based on your requirement.
You have to create relationships between your entities by using a set of annotations like: #ManyToOne, #OneToMany, #ManyToMany or #OneToOne... and other annotations if needed.
In your case I am not really sure you need an InvoiceInfo table, as the Invoice table can (or should) already contains the list of products.
I would suggest you the following relationships:
Product
#Entity
#Table(name = "product")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "family_id")
private long familyId;
#Column(name = "product_name")
private String productName;
#Column(name = "product_category")
private String productCategory;
#Column(name = "product_quantity")
private int productQuantity;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "invoice_id", referencedColumnName = "id")
private Invoice invoice;
//getters and setters
}
Invoice
#Entity
#Table(name = "invoice")
public class Invoice {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "invoice_id")
private Long id;
#Column(name = "provider_id")
private Long providerId;
#Column(name = "total")
private int invoiceTotal;
#Column(name = "date")
private Date invoiceDate;
#OneToMany(mappedBy = "product")
private List<Product> products;
//getters and setters
}
As your table InvoiceInfo no longer exists, you just have to insert you data in two table like this:
Invoice invoice = invoiceRepository.save(invoice);
Product product = new Product();
// Set the other properties
product.setInvoice(invoice);
productRepository.save(product);

Create entity using join in jpa hibernate

I'm stuck with a problem in Java, hibernate (jpa)
So, I have 2 classes: Class and Classroom, each one being entities
#Entity
#Table(name = "CLASSES")
public class Class {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="ID")
private Long id;
#Column(name = "TEACHER_ID")
private Long teacherId;
#Column(name = "NAME")
private String name;
#Column(name = "YEAR")
private Integer year;
#Column(name = "SECTION")
private String section;
}
#Entity
#Table(name = "CLASSROOMS")
public class Classroom {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private Long id;
#Column(name = "NAME")
private String name;
#Column(name = "LOCATION")
private String location;
#Column(name = "CAPACITY")
private Integer capacity;
}
Also, I have another java class called Planner which connect these two classes (their tables - using classroom_id and class_id); I have a table for this Planner
#Entity
#Table(name = "PLANNERS")
public class Planner {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private Long id;
#Column(name = "CLASSROOM_ID")
private Long classroomId;
#Column(name = "CLASS_ID")
private Long classId;
#Column(name = "STARTTIME")
private Time startTime;
#Column(name = "ENDTIME")
private Time endTime;
#Column(name = "DATA")
private Date date;
}
What I need: a new entity (or just output data) which will include all fields from PLANNERS, field NAME from CLASSES and field NAME from CLASSROOMS.
In SQL, this query is:
select M.classroom_id, M.class_id, M.starttime, M.endtime, M.data, CL.NAME AS "ROOM NAME (FROM CLASSROOMS)", C.NAME AS "COURSE NAME (FROM CLASSES)" FROM PLANNERS M INNER JOIN CLASSROOMS CL ON CL.ID = M.CLASSROOM_ID INNER JOIN CLASSES C ON C.ID = M.CLASS_ID
(inner join using classroom_id and class_id)
How can I do this on hibernate jpa? I want to get the objects (rows) returned by the above query.
I searched a lot, I find about join column, other annotations (e.g. OneToMany etc) but I didn't succeed, so I need help

OneToMany could not determine type for SpringBoot/SQLite3

I have a problem with the relationship oneToMany. I created tables in SQLite DB, this is my tables:
I created the two models CategoryModel and ProductModel.
ProductModel is:
#Entity
#Table(name = "Product_Category")
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class ProductModel {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long product_id;
private Long category_id;
private String name;
private String description;
private int numberOfProduct;
private String image;
private int price;
#JoinColumn(name = "country_id", nullable = false)
private CategoryModel category;
//geter's and seter's
}
My CategoryModel:
#Entity
#Table(name = "Category")
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class CategoryModel {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String category_name;
private String category_description;
private String image_path;
#OneToMany( mappedBy = "category")
private Set<ProductModel> category;
//Geter's and Seter's
My Repository:
public interface CategoryRepository extends JpaRepository<CategoryModel, Long> {
#Query("SELECT * "
+ "FROM Product_Category d INNER JOIN d.categoryModel e")
List<ProductModel> fetchEmpDeptDataInnerJoin();
}
I do not understand where I make a mistake. I have this error:
Could not determine type for:
com.dar.darkozmetika.models.CategoryModel, at table: product_category,
for columns: [org.hibernate.mapping.Column(category)]
1) Add #ManyToOne annotation:
#ManyToOne
#JoinColumn(name = "country_id", nullable = false)
private CategoryModel category;
2) Remember that you are using JPQL, not SQL (unless you sent native="true"):
#Query("SELECT p "
+ "FROM ProductModel p INNER JOIN p.category c")

Categories