hibernate select query from child table - java

I am pretty new to hibernate. I have a two tables having one to many relationship. Two tables are:
public class Pashmina implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "sq_pashmina_id")
#SequenceGenerator(name = "sq_pashmina_id", sequenceName = "sq_pashmina_id")
#Column(name = "PASHMINA_ID")
private int pashminaId;
#Column(name = "PASHMINA_NAME")
private String pashminaName;
#Column(name = "PRICE")
private double price;
#Column(name = "ADDED_AT", insertable = false)
#Temporal(TemporalType.TIMESTAMP)
private Date addedAt;
#Column(name = "CATEGORY")
private String category;
#Column(name = "ENABLED", insertable = false)
private Character enabled;
#OneToMany(mappedBy = "colourId", fetch = FetchType.EAGER)
private Set<PashminaColour> pashminaColor = new HashSet<PashminaColour>();
#OneToMany(mappedBy = "imageId", fetch = FetchType.EAGER)
private Set<Image> images = new HashSet<Image>();
#OneToMany(mappedBy = "descriptionId", fetch = FetchType.EAGER)
private Set<Description> descriptions = new HashSet<Description>();
//getter and setter method
This is a parent class and it have one to many relationship with Image table
public class Image implements Serializable {
#Id
#Column(name = "IMAGE_ID")
private int imageId;
#Column(name = "IMAGE_NAME")
private String imageName;
#JoinColumn(name = "PASHMINA_ID", referencedColumnName = "PASHMINA_ID")
#ManyToOne
private Pashmina pashmina;
Now I want to select a imagenames from Image class using its parent class's id (ie: pashminaId)
eg:
SELECT IMAGE_NAME FROM TBL_IMAGE WHERE PASHMINA_ID = 'some_digit';
How can i pass pashminaId in image class as there is no pashminaId it only have an Object creation of Parent class Pashmina.
So, How can i achieve this in hibernate?
Let me know if you don't understand me.
Thanks! Hoping for positive response.

As Hibernate treats objects instead of SQL tables, you can simply access the pashmina object from your image object, and in your query you will be treating java objects/POJOs, so you can acccess it via Image.pashmina.pashminaId.
So you can write the following query:
String hql = "select I.imageName FROM Image I WHERE I.pashmina.pashminaId = 10";
Query query = session.createQuery(hql);
List results = query.list();

Related

How to load two collections of related entities with a minimum number of sql queries?

I have the entities:
Bank:
public class Bank {
#Id
#Column(name = "bank_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private UUID id;
#Column(name = "bank_name")
private String bankName;
#OneToMany(orphanRemoval = true, cascade = CascadeType.ALL,
mappedBy = "bank", fetch = FetchType.LAZY)
private List<CreditDetails> creditDetails = new ArrayList<>();
#OneToMany(orphanRemoval = true, cascade = CascadeType.ALL,
mappedBy = "bank", fetch = FetchType.LAZY)
private List<Client> clients = new ArrayList<>();
}
Client:
public class Client {
#Id
#Column(name = "client_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
#Column(name = "client_name")
private String clientName;
#Column(name = "client_surname")
private String clientSurName;
#Column(name = "client_full_name")
private String clientFullName;
#Column(name = "telephone_number")
private Long telephoneNumber;
#Column(name = "email")
private String email;
#Column(name = "passport_number")
private Long passportNumber;
#ManyToOne(
cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
#JoinColumn(name = "bank_id")
private Bank bank;
#OneToMany(cascade = CascadeType.ALL,
mappedBy = "client")
private List<CreditOffer> creditOffers = new ArrayList<>();
}
Credit Details:
public class CreditDetails {
#Id
#Column(name = "credit_details_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
#Column(name = "credit_limit")
private BigDecimal creditLimit;
#Column(name = "credit_percent")
private BigDecimal creditPercent;
#ManyToOne(targetEntity = Bank.class, cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, fetch = FetchType.EAGER)
#JoinColumn(name = "bank_id")
private Bank bank;
#OneToMany(cascade = CascadeType.ALL,
mappedBy = "creditDetails")
List<CreditOffer> creditOffers = new ArrayList<>();
}
My task is to load Clients and Credit Details with the least number of requests using Spring Data.
I tried to solve this problem using graphs, I added the following construction above the bank entity:
#NamedEntityGraph(name = "BankWithClientsAndDetails", attributeNodes = {
#NamedAttributeNode(value = "creditDetails"),
#NamedAttributeNode(value = "clients",subgraph = "ClientWithBank")
})
However, when calling the method, I received a MultyBagFetchException, googled that this occurs due to the fact that a Cartesian product is obtained in the request.
Next, I tried to solve the problem by writing a sql query manually, I made a test method of the following form:
#Query(value = "SELECT * FROM banks \n" +
"JOIN clients ON clients.bank_id = banks.bank_id \n" +
"JOIN credit_details ON credit_details.bank_id = banks.bank_id \n" +
"WHERE banks.bank_id = :id",nativeQuery = true)
Optional<Bank> findBankWithSubEntitiesById(#Param(value = "id") UUID id);
The number of requests has remained huge, since related entities have more related entities, and those have one more. At this stage, my hands dropped and I came to you to ask for help. How would you solve this situation? Do I really have to put up with N + 1 in my case. I would be grateful for any help
Using just JOIN in your query merely narrows the results, eg - it won't loads banks without any clients and credit details.
You can tell hibernate to load each of these associations eagerly using JOIN FETCH jpql keyword.
SELECT bank
FROM Bank bank
JOIN FETCH bank.clients
JOIN FETCH bank.creditDetails
WHERE bank.id = :bankId
Keep in mind that this is a jpql query, so you have to remove nativeQuery = true parameter. Also, note that by default, join is inner and not outer - meaning that this query also won't return a bank without clients or credit details. You can change that by using LEFT JOIN FETCH, but that will reduce performance, so choose whatever strategy suits best your use-case.
Further reading

how to find id of foreign key in hibernate

I have two entities viz:
State
#Entity
#Table(name = "State")
public class StateEntity {
#Column(name = "id", length = 36, nullable = false, unique = true)
private String id;
#ManyToOne (fetch = FetchType.LAZY)
#JoinColumn(name = "InsurerId", nullable = false)
private InsurerEntity insurer;
#Column(name ="StateName", length = 50, nullable = false)
private String stateName;
//getters and setters
}
Insurer
#Entity
#Table(name = "Insurer")
public class InsurerEntity {
#Column(name = "InsurerId", length = 36, nullable = false, unique = true)
private String insurerId;
#Column(name = "InsurerName", length = 100, nullable = true)
private String insurerName;
#OneToMany(mappedBy = "state", fetch = FetchType.LAZY)
private List<StateEntity> stateEntityList;
//getters and setters
}
the insurer's id gets saved in state database and I want to retrieve it using hibernate query but I cant't seem to find the solution for that
How to write this query SELECT InsurerId FROM State; in Hibernate query using CriteriaBuilder, CriteriaQuery and Root..
If you want to select all Insurers's Ids for all states:
String selectionQuery = "SELECT s.insurer.insurerId FROM State s";
List<String> insurersIds = session.createQuery(selectionQuery).list();
If you want to select the Insurer's Id of a certain state:
String selectionQuery = "SELECT s.insurer.insurerId FROM State s WHERE s.id = :stateId";
String insurerId = (String) session.createQuery(selectionQuery).setParameter("stateId", stateId).getSingleResult(); //This should be placed in a try/catch block to handle org.hibernate.NonUniqueResultException
Edit:
You should update your Insurer entity as Prasad wrote in his answer.
for this you have to map both the class as in put #oneToMany annotation in class InsurerEntity as well
#OneToMany(fetch = FetchType.LAZY,mappedBy="StateEntity", cascade = CascadeType.ALL)
private List< StateEntity > StateEntitys;
and when you fetch states you will also get object of InsurerEntity in it from where you can access it with the getter

Get records from two table in relation many to many

I have two table in relation many to many
public class Repertoire {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(nullable = false, unique = true)
private Integer id;
private String name;
private Integer dayWeek;
#ManyToMany(cascade = CascadeType.REMOVE)
#JoinTable(
name = "repertoire_seance",
joinColumns = { #JoinColumn(name = "repertoire_id")},
inverseJoinColumns = {#JoinColumn(name = "seance_id")}
)
List<Seance> seances = new ArrayList<>();
}
and
public class Seance {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(nullable = false, unique = true)
private Integer id;
private java.time.LocalTime displayTime;
#ManyToOne
private Film film;
#Column(length=127)
private String kind;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
private Hall hall;
#OneToMany(mappedBy = "reservationSeance")
#JsonIgnore
private List<Reservation> reservations = new ArrayList<>();
}
Hibernate create linked tabel repertoire_seance is posible get seances by seancesId and repertoire.dayWeek using spring data (JpaRepository) something like that findBySeanceIdAndRepertoireDayWeek()?
You could achieve this by writing an HQL.
It would look something like this:
select s from Repertoire r inner join r.seances s where r.dayWeek ="Your Value" and s.id = "Your Id Value"

Use Hibernate Formula annotation for reference loading

I have 3 entities - Storage, Item and Relation. Storage has several Item entities and items are bound by Relation entities. And relations can bind items from different storage. For simplification let say I want to load relation by query and want to do it fast. So now I have 3 query - loading for Storage, loading for all Items under storage and load of relation (List<Relation> relations field).
Now I want to tell hibernate how to load Collection<Relation> extRelation field. I tried #Formula, #CalculatedColumn and different combination of #ManyToMany and #JoinFormula. But generated query is wrong (or ignores my query). Also I cannot use #OneToMany because of https://hibernate.atlassian.net/browse/HHH-9897 bug.
Latest Exception is:
Caused by: org.h2.jdbc.JdbcSQLException: Table
"TEST_STORAGES_TEST_RELATIONS" not found; SQL statement:
SELECT extrelatio0_.test_storages_storage_id AS test_sto1_2_0_
,extrelatio0_.extRelation_from_item_id AS extRelat2_3_0_
,extrelatio0_.extRelation_to_item_id AS extRelat3_3_0_
,relation1_.from_item_id AS from_ite1_1_1_
,relation1_.to_item_id AS to_item_2_1_1_
,relation1_.relation_id AS relation3_1_1_
,relation1_.storage_id AS storage_4_1_1_
FROM test_storages_test_relations extrelatio0_
INNER JOIN test_relations relation1_ ON extrelatio0_.extRelation_from_item_id = relation1_.from_item_id
AND extrelatio0_.extRelation_to_item_id = relation1_.to_item_id
WHERE extrelatio0_.test_storages_storage_id = ?
My entities:
#Entity
#Table(name = "test_storages")
public class Storage {
#Id
#Column(name = "storage_id")
private BigInteger storageId;
private String name;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, targetEntity = Item.class)
#JoinColumn(name = "storage_id", updatable = false)
#MapKey
private List<Item> items;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, targetEntity = Relation.class)
#JoinColumn(name = "storage_id", updatable = false)
#Fetch(org.hibernate.annotations.FetchMode.SELECT)
private List<Relation> relations;
#ManyToMany()
#JoinColumnsOrFormulas({
#JoinColumnOrFormula(formula =
#JoinFormula(
value = "(select dep.from_item_id, dep.to_item_id from test_relations dep where dep.storage_id = ?)"
)
)
})
private Collection<Relation> extRelation;
}
#Entity
#Table(name = "test_items")
public class Item {
#Id
#Column(name = "item_id")
private BigInteger itemId;
private String name;
#Column(name = "storage_id")
private BigInteger storageId;
}
#Entity
#Table(name = "test_relations")
public class Relation {
#Column(name = "relation_id")
private BigInteger relationId;
#Column(name = "storage_id")
private BigInteger storageId;
#EmbeddedId
private RelationPK pk;
}
#Embeddable
public class RelationPK implements Serializable {
#Column(name = "from_item_id")
private BigInteger fromItemId;
#Column(name = "to_item_id")
private BigInteger toItemId;
}
All sources available on https://github.com/ainlolcat/test_hibernate_formula

How to create a namedquery of manytomany entity?

Brand
public class Brand implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "BrandID", nullable = false)
private Integer brandID;
#Basic(optional = false)
#Column(name = "BrandName", nullable = false, length = 100)
private String brandName;
#Basic(optional = false)
#Column(name = "Description", nullable = false, length = 1000)
private String description;
#Column(name = "Is_Visible")
private Boolean isVisible;
#JoinTable(name = "brandcategory", joinColumns = {
#JoinColumn(name = "BrandID", referencedColumnName = "BrandID")}, inverseJoinColumns = {
#JoinColumn(name = "CategoryID", referencedColumnName = "CategoryID")})
#ManyToMany(fetch = FetchType.EAGER)
private Collection<Category> categoryCollection;
#OneToMany(mappedBy = "brand", fetch = FetchType.EAGER)
private Collection<Product> productCollection;
I want to retrive the Brand IDs from table brandcategory whoes categoryID = :categoryID
how can i createnamed query for it in entity brand?
this does not work:
#NamedQuery(name = "Brand.getBrandListByCategory",
query = "SELECT b FROM Brand b WHERE b.brandID =
(SELECT bc.brandID
FROM b.brandctegory bc
WHERE bc.category.categoryID = :categoryID)")
If I understand correctly, you want all the brands belonging to a category. Why don't you simply make the association bidirectional. You could then just do:
Category category = em.find(Category.class, categoryId);
return category.getBrands();
If it's unidirectional, then you'll need a query, but it's much simpler that the one you tried:
select b from Brand b inner join b.categoryCollection category
where category.id = :categoryId;
Your query doesn't make sense: it uses a non-existing association (b.brandcategory). Remember that JPQL uses entities, their persistent fields and associations to other entities. And nothing else. Tables don't exist in JPQL.
AFAIK, you cant go out of a entity boundary, when creating queries in entity class.
Instead use .createNativeQuery() method of the entity manager, to create complex and mixed queries.

Categories

Resources