How to map resultset into composite object in mapper class - java

I have query which will return 8 columns for order placement POC, First 4 will be same for few rows(person details) and remaining 4 alone will differ(order details). Its a non normalized table.
COL1 COL2 COL3 COL4 COL5 COL6 COL7 COL8
-----------------------------------------------------
a aaa bbb ccc ddd eee fff ggg
a aaa bbb ccc hhh iii jjj kkk
My object looks like
class OrderBook{
int id;
int name;
String age;
String mailId;
List<Order> orderList;
}
class Order{
String productName;
int price;
int quantity;
String address;
}
how can i loop through the result set and map the rows into the Orderbook object. Response should look something like below
{
"id": 1,
"name": "dude",
"age" : 22,
"mailId": "dude#abc.com",
"orderList": [
{
"productName": "Milk",
"price":23,
"quantity":2,
"address": "dude, 1st street"
},
{
"productName": "Egg",
"price":5,
"quantity":10,
"address": "dude, 1st street"
}
]
}
I dont know how to loop it here
while(rs.next()){
???
}

You should convert resultset to DataObject (OrderBook) firstly.
List<OrderBook> list = new ArrayList<>();
while(rs.next()){
OrderBook orderBook = mapToOrderBook(rs);
list.add(orderBook);
}
Few basic functions which you should write.
private List<OrderBook> getOrderBooks();
private OrderBook mapToOrderBook(ResultSet rs);
If you don't know how to get data from resultset:
https://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html
Then you can use jackson to convert List to json data.
Spring mvc already handled it for you.
#RequestMapping("/orderbooks")
public List<OrderBook> getOrderBooks() {
return orderbookService.getOrderBooks();
}

If you are using ResultSet directly you have to implement transformers directly from RS to Object instance. And use it from your DAO layer Something like:
#Override
public User getByID(int id) {
OrderBook book = new OrderBook();
try {
PreparedStatement select = OrderBookTransformer.getInstance().getSelectStatementById(id);
ResultSet rs = select.executeQuery();
while (rs.next()) {
book = OrderBookTransformer.getInstance().fromRsToObject(rs);
}
} catch (SQLException e) {
log.error(e);
}
return book;
}
Where OrderBookTransformer could be like:
#Override
public OrderBook fromRsToObject(ResultSet rs) {
OrderBook book = new OrderBook();
try {
user.setId(rs.getInt("id"));
user.setName(rs.getInt("name"));
user.setAge(rs.getString("age"));
// set other fields
} catch (SQLException e) {
log.error(e);
}
return user;
}
For the initialisation transformer I used the Singleton pattern:
public class OrderBookTransformer implements BaseTranformer<OrderBook> {
private static final Logger log = Logger.getLogger(OrderBookTransformer.class);
private static OrderBookTransformer instance = null;
protected OrderBookTransformer() {
}
public static OrderBookTransformer getInstance() {
if (instance == null) {
instance = new OrderBookTransformer();
}
return instance;
}
And select statement something like:
#Override
public PreparedStatement getSelectStatementById(int id) {
PreparedStatement select = null;
try (Connection connection = ConnectionManager.getConnection()) {
select = connection
.prepareStatement("SELECT FROM order_books WHERE id = ?");
select.setInt(1, id);
} catch (SQLException e) {
log.error(e);
}
return select;
}
My suggestion will be to use Spring Data instead of processing the Result Set directly.
You will need to do just a few more steps:
add spring data dependency to your build tool
add JPA annotations to your model with relations to it:
#Entity
class OrderBook {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Integer name;
private String age;
private String mailId;
#ElementCollection(targetClass = Order.class, fetch = FetchType.EAGER)
#CollectionTable(name = "orders", joinColumns = #JoinColumn(name = "book_id"))
private List<Order> orderList;
// no args constructor + getters/setters
}
#Entity
class Order {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private String productName;
private Integer price; // consider use Double here
private Integer quantity;
private String address;
}
create a repository for this class:
public OrderBookRepository implements JpaRepository<OrderBook, Integer> {}
and use it for retrieving data from DB.

Related

Hibernate query returns null, but entity gets loaded on object anyway

This will take some explaining. So, I have an entity called Invoice and a related table called Errors, which is used to store some processing errors.
In a DAO class, I have a query for fetch the errors with some specific criteria:
public Errors loadLastError(Invoice i) {
try (Session session = factory.openSession()) {
Query query = session.createQuery("select er from Errors er" +
" inner join er.invoice i" +
" where er.invoice = :invoice" +
" and i.status <> :code" +
" and i.proccessStatus = :status" +
" order by er.id desc");
query.setParameter("invoice", invoice);
query.setParameter("code", "001");
query.setParameter("status", "form_error");
var result = query.getSingleResult();
return (Errors) result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
This works fine: will only get results when the conditions match. When they don't, I get the expected null result where this method is called:
this.invoice.setError(loadLastError(this.invoice);
When inspecting the code, I can see that the this.invoice object was updated correctly with a null result.
But, as soon as I pass this object invoice to another class in order to do some proccessing (send notifications basically by JSON), it gets there with a Errors object loaded, as if my original query had actually found something, which it didn't.
The following are a shortened example of my entity classes:
The Invoice:
#Entity
#DynamicUpdate
#Table(name = "data.invoice")
#TypeDef(
name = "pgsql_enum",
typeClass = PostgreSQLEnumType.class
)
public class Invoice implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#JsonIgnore
#Column(name = "proccessStatus")
private String proccessStatus;
#JsonIgnore
#Column(name = "status")
private String status;
#JsonIgnore
#OneToOne(mappedBy = "invoice", fetch = FetchType.LAZY)
private Errors errors;
public Integer getId() {
return id;
}
public String getProccessStatus() {
return proccessStatus;
}
public void setProccessStatus(String proccessStatus) {
this.proccessStatus= proccessStatus;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status= status;
}
public Errors getErrosr() {
return errors;
}
public void setErrors(Errorserrors) {
this.errors= errors;
}
The Errors entity:
#Entity
#Table(name = "data.invoice_errors")
public class Errors implements Serializable {
public Errors() {
}
public Errors(Invoice invoice, String error) {
this.invoice= invoice;
this.error = error;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#OneToOne
#JoinColumn(name = "id_invoice")
private Invoice invoice;
private String error;
#Column(name = "created_at")
private LocalDateTime createdAt;
public Integer getId() {
return id;
}
public Invoice getInvoice() {
return invoice;
}
public void setInvoice(Invoice invoice) {
this.invoice = invoice;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
This behaviour seems very strange and I don't know how to diagnose it and what may be wrong. Any input would be very appreciated.
What I'm expecting is that the entity don't get updated out of nowhere with a result that wasn't found initially because it simply didn't match the search criteria in the first place.
I'm a colossal idiot. The issue was that the notification class was refreshing the model. Changed the database search to go after the refresh and fixed the problem.

Need to save two tables from different jsp pages with foreign key relationship using hibernate dao implementation method

Image of table relationship reference
After submit from bank jsp page and after submit from card jsp all in one image because of limitation of newbie
I am new to stackoverflow as well SPRING. I have tried to create two tables with foreign key concept . I have followed some examples on stackoverflow as well as from other resourcefull websites and manged to create two tables with onetomany relationship. But the problem is i have to get the first row id under cart_id column when i submit from card jsp page. Instead after submit from card jsp page there is new row created under bankadmin table and it's id is being returned. I am confused and have no idea how to correct ot resolve this issue. Please be kind and guide me. And also i have been searching for a week in stackoverflow couldn't find anything that helped me. Thanks in advance.
Bankadmin Model
#Entity
#Table(name = "bankAdmin")
public class bankAdmin implements Serializable{
#GeneratedValue(strategy=GenerationType.AUTO)
#Column (name = "bcode", nullable=false)
#Id private int bcode;
#Column (name = "bname")
private String bname;
#Column (name = "address")
private String address;
#Column (name = "phno")
private int phno;
#OneToMany(mappedBy="bankAdmin",cascade = CascadeType.ALL)
private Set<Cards> cards;
Card model
#Entity
#Table(name = "cards")
public class Cards implements Serializable {
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="cname", unique=true)
#Id private int cname;
#Column (name = "ctype")
private String ctype;
#Column (name = "min_sal")
private int min_sal;
#Column (name = "year_fee")
private int year_fee;
#Column (name = "rewards")
private String rewards;
#Column (name = "jperks")
private String jperks;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name="cart_id", nullable=false)
private bankAdmin bankAdmin;
public Cards(){}
public Cards(String ctype, int min_sal, int year_fee, String rewards, String jperks, bankAdmin b){//int cname,
this.ctype=ctype;
this.min_sal=min_sal;
this.year_fee=year_fee;
this.jperks=jperks;
this.rewards=rewards;
this.bankAdmin=b;
}
public bankAdmin getBankAdmin() {
return bankAdmin;
}
public void setBankAdmin(bankAdmin bankAdmin) {
this.bankAdmin = bankAdmin;
}
CardDaoImpl
public class CardsDaoImpl implements CardsDao{
#Autowired
SessionFactory sessionfactory;
public void save(Cards cards) {
Session session = null;
Transaction tx = null;
try
{
session = this.sessionfactory.openSession();
tx = session.beginTransaction();
bankAdmin bankadmin =new bankAdmin(); //=null;
String _ctype = cards.getctype();
int _min_sal = cards.getmin_sal();
int _year_fee = cards.getyear_fee();
String _rewards = cards.getrewards();
String _jperks = cards.getjperks();
Set<Cards> card = new HashSet<Cards>();
Cards config = new Cards(_ctype,_min_sal,_year_fee,_rewards,_jperks,bankadmin);
card.add(config);
bankadmin.setcards(card);
// System.out.println("bankadmin: before " + bankadmin);
// bankadmin.setbname(bankadmin.getbname());// "SBI"
// bankadmin.setphno(bankadmin.getphno());//1234567890
// bankadmin.setaddress(bankadmin.getaddress());//Bengaluru
// System.out.println("bankadmin: after " + bankadmin);
// int _cname = cards.getcname();
// int bankadmin = bankadmin.getbcode();
//_cname,_ctype,_min_sal,_year_fee,_rewards,_jperks,bankadmin
// card.add(config);
// config.setBankAdmin(cards.getBankAdmin(bankadmin));
// config.setcname(cards.getcname());
// config.setctype(cards.getctype());
// config.setmin_sal(cards.getmin_sal());
// config.setyear_fee(cards.getyear_fee());
// config.setrewards(cards.getrewards());
// config.setjperks(cards.getjperks());
// config.setBankAdmin(cards.getBankAdmin());
session.save(bankadmin);
session.save(config);
tx.commit();
}
catch (HibernateException e)
{
e.printStackTrace();
}
finally
{
session.close();
}
}
// get lms lights config from DB
public List<Cards> Ccards() {
Session session = null;
// Transaction tx = null;
List<Cards> Ccards = null;
try{
session = this.sessionfactory.openSession();
Ccards = session.createQuery("FROM Cards").list();
System.out.println("cards dao impl executed...");
System.out.println("cards config : "+ Ccards.toString());
}
catch (Exception e)
{
System.out.println("bankAdmin Dao impl Ex : " + e);
}
finally
{
session.close();
}
return Ccards;
}
}
BankDaoImpl
public class bankAdminDaoImpl implements bankAdminDao{
#Autowired
SessionFactory sessionfactory;
public void save(bankAdmin badmin) {
Session session = null;
Transaction tx = null;
try
{
session = this.sessionfactory.openSession();
tx = session.beginTransaction();
// bankAdmin bankadmin = new bankAdmin();
bankAdmin config = new bankAdmin();
config.setbcode(badmin.getbcode());
config.setbname(badmin.getbname());
config.setaddress(badmin.getaddress());
config.setphno(badmin.getphno());
session.save(config);//save//persist
tx.commit();
}
catch (HibernateException e)
{
e.printStackTrace();
}
finally
{
session.close();
}
}
// get lms lights config from DB
public List<bankAdmin> BbankAdmin() {
Session session = null;
// Transaction tx = null;
List<bankAdmin> BbankAdmin = null;
try{
session = this.sessionfactory.openSession();
BbankAdmin = session.createQuery("FROM bankAdmin").list();
System.out.println("bankAdmin dao impl executed...");
System.out.println("bankAdmin config : "+ BbankAdmin.toString());
}
catch (Exception e)
{
System.out.println("bankAdmin Dao impl Ex : " + e);
}
finally
{
session.close();
}
return BbankAdmin;
}
}
Okay. I have posted the solution to your problem.
First of all, Spring framework is wonderful to work with. The framework got a lot of features, that you should take advantage of. I am not sure if I will be able to cover everything in this post, so please feel free to ask me.
I have created a simple Spring Boot application. I got total of 6 files that are important which is posted below.
Notice that I renamed your classes to CamelCase with capital starting letter. such as BankAdmin. This is considered the standard way of writing java classes. Also note that i renamed Cards to Card, so remember to rename your table in the database aswell. Also remember to rename the bankadmin table to bank_admin.
There are thee annotations that you have to look into. #Transactional, #Autowired, and PersistenceContext.
So a quick and easy explanation. #Transactional manages all transactions for you, so you do not have to begin and commit transactions. #Autowired creates objects for you, so you do not have to manage your object dependencies yourself. PersistenceContext basically creates and EntityManager for you and manages it for you. You do not have to create session nor EntitManagerFactory. These three annotations are explained very brief, so you should read about them yourself.
I also removed #Table(name = "bankAdmin") and #Table(name = "cards"). JPA can lookup these tables automatically if you follow the standard way of naming classes and database tables. It is actually pretty simple, but I still encourage you to look into this by yourself. In short, capital camelcase is turned into lowercase with _ inbetween each word that start with a capital letter. I.e. If your class name is BankAdmin then JPA will automatically look for table named bank_admin in your database.
application.properties - details about your database
spring.datasource.url=jdbc:mysql://localhost:3306/stackoverflow?useSSL=false
spring.datasource.username = root
spring.datasource.password = root
spring.jpa.show-sql = true
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.ddl-auto = update
The below code is only written to test the functionality
#SpringBootApplication
public class StackoverflowApplication {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(StackoverflowApplication.class, args);
//Calling a class that is only made with the purpose of testing
Verification ts = ctx.getBean(Verification.class);
ts.run();
}
}
#Component
class Verification{
#Autowired
private BankAdminDao bad;
#Autowired
private CardsDao cd;
void run(){
//Create a new BankAdmin
BankAdmin ba = new BankAdmin();
ba.setAddress("someStreet");
ba.setPhno(12341234);
ba.setBname("myBanker");
//Create two cards and add them to a HashSet.
Card c1 = new Card("Visa", 1000, 1999, "Alot of", "Babes", ba);
Card c2 = new Card("Master Card", 2000, 500, "someThing", "anotherThing", ba);
Set<Card> cardList = new HashSet<>();
cardList.add(c1);
cardList.add(c2);
//Create a associatio between the BankAdmin and list of Cards
ba.setCards(cardList);
//Save them to the database.
bad.save(ba);
//Here we add a Card to an existing BankAdmin with the id 6 in the database.
//Create a new Card.
//The BankAdmin is set to null, because we not have not yet loaded the BankAdmin
Card c3 = new Card("Visa", 9999, 1337, "Alot of", "Male Babes", null);
//Save Card c3 with the BankAdmin id 6
cd.save(c3, 6);
}
}
BankAdmin
#Entity
public class BankAdmin implements Serializable{
#GeneratedValue(strategy=GenerationType.AUTO)
#Column (name = "bcode", nullable=false)
#Id private int bcode;
#Column (name = "bname")
private String bname;
#Column (name = "address")
private String address;
#Column (name = "phno")
private int phno;
#OneToMany(mappedBy="bankAdmin",cascade=CascadeType.ALL)
private Set<Card> cards;
//Getters and Setters have been removed to reduce the amount of code.
}
BankAdminDao
#Repository
//Transactional makes transaction automatical, so you do not have to begin and commit transactions yourself!
#Transactional
public class BankAdminDao{
//This makes your life a lot eaier!
//It will take care of your EntitManagerFactory and Sessions
#PersistenceContext
EntityManager em;
public void save(BankAdmin bank) {
em.merge(bank);
}
//get lms lights config from DB
public List<BankAdmin> getAllBankAdmin() {
List<BankAdmin> bankList = (List<BankAdmin>)em.createQuery("SELECT b FROM BankAdmin b");
return bankList;
}
public BankAdmin getBankAdmin(int bankId) {
return em.find(BankAdmin.class, bankId);
}
}
Card
#Entity
public class Card implements Serializable {
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="cname", unique=true)
#Id private int cname;
#Column (name = "ctype")
private String ctype;
#Column (name = "min_sal")
private int min_sal;
#Column (name = "year_fee")
private int year_fee;
#Column (name = "rewards")
private String rewards;
#Column (name = "jperks")
private String jperks;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name="cart_id", nullable=false)
private BankAdmin bankAdmin;
public Card(){}
public Card(String ctype, int min_sal, int year_fee, String rewards, String jperks, BankAdmin b){
this.ctype=ctype;
this.min_sal=min_sal;
this.year_fee=year_fee;
this.jperks=jperks;
this.rewards=rewards;
this.bankAdmin=b;
}
public BankAdmin getBankAdmin() {
return bankAdmin;
}
public void setBankAdmin(BankAdmin bankAdmin) {
this.bankAdmin = bankAdmin;
}
}
CardDao
#Repository
#Transactional
public class CardsDao{
#PersistenceContext
EntityManager em;
#Autowired
BankAdminDao bad;
public void save(Card cards, int bankId) {
BankAdmin bank = bad.getBankAdmin(bankId);
cards.setBankAdmin(bank);
bank.getCards().add(cards);
em.merge(bank);
}
public List<Card> getAllCards() {
List<Card> cardList = (List<Card>)em.createQuery("SELECT c FROM Cards c");
return cardList;
}
public Card getCard(int cardId){
return em.find(Card.class, cardId);
}
}

How to add Hibernate HQL/ SQL results (List) to JavaFX TableView (ObservableList) using property?

I'm using hibernate 5.0.7 and JavaFX For UI's.I get a list of data from database,i tried to show them in a tableView,but no thing shown in tableView.
Here is table structure
CREATE TABLE product
(
idproduct serial NOT NULL,
namefr character varying(50),
qtyinhand double precision,
sellprice double precision,
CONSTRAINT product_pkey PRIMARY KEY(idproduct)
)
Object Relational Mapping:
package model;
#Entity
#Table(name = "Product")
#Access(AccessType.PROPERTY)
public class Product {
private LongProperty idProduct;
private StringProperty nameFr;
private DoubleProperty qtyInHand;
private DoubleProperty sellPrice;
public Product() {
idProduct = new SimpleLongProperty();
nameFr = new SimpleStringProperty();
qtyInHand = new SimpleDoubleProperty();
sellPrice = new SimpleDoubleProperty();
}
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "product_seq_gen")
#SequenceGenerator(name = "product_seq_gen", sequenceName = "product_idproduct_seq")
#Column(name = "idproduct", unique = true, nullable = false)
public Long getIdProduct() {
return idProduct.get();
}
public LongProperty idProductProperty() {
return idProduct;
}
public void setIdProduct(Long idProduct) {
this.idProduct.set(idProduct);
}
#Column(name = "nameFr")
public String getNameFr() {
return nameFr.get();
}
public StringProperty nameFrProperty() {
return nameFr;
}
public void setNameFr(String nameFr) {
this.nameFr.set(nameFr);
}
#Column(name = "qtyInHand")
public double getQtyInHand() {
return qtyInHand.get();
}
public DoubleProperty qtyInHandProperty() {
return qtyInHand;
}
public void setQtyInHand(double qtyInHand) {
this.qtyInHand.set(qtyInHand);
}
#Column(name = "sellPrice")
public double getSellPrice() {
return sellPrice.get();
}
public DoubleProperty sellPriceProperty() {
return sellPrice;
}
public void setSellPrice(double sellPrice) {
this.sellPrice.set(sellPrice);
}
}
I'm using hibernate to retrieve the list of products from database:
public ObservableList<Product> findAll() {
try {
session.beginTransaction();
Query query = session.createSQLQuery("select * from product");
ObservableList<Product> list = FXCollections.observableArrayList(query.list());
session.getTransaction().commit();
session.close();
return list;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
After that i set the table view to show data:
tcID.setCellValueFactory(new PropertyValueFactory<Product, Long>("idProduct"));
tcNameFR.setCellValueFactory(new PropertyValueFactory("nameFr"));
tcQtyInHand.setCellValueFactory(new PropertyValueFactory("qtyInHand"));
tcSellPrice.setCellValueFactory(new PropertyValueFactory<Product, Double>("sellPrice"));
ProductDAO dao=new ProductDAO();
tableView.getItems().addAll(dao.findAll());
After that i can't get item showed in tablview, instead of that when i debug
i notice that dao.findAll()returns a list with size>0,but table don't show any thing.
Since you are using a SQL query, Hibernate doesn't know to associate your entity with the query. You can do
SQLQuery query = session.createSQLQuery("select * from product");
query.addEntity(Product.class);
ObservableList<Product> list = FXCollections.observableArrayList(query.list());
It's probably better to use a HQL query though:
// the really concise, but not very readable "from Product" works as the query too
Query query = session.createQuery("select p from Product as p");
ObservableList<Product> list = FXCollections.observableArrayList(query.list());

Mapping hibernate entity with Jackson annotation

I'm working with Spring, hibernate and MySql but I have some problem with seralization of query result.
First in my entity I added #JsonManagedReference on Set structure (#OneToMany side) and #JsonBackReference on single object reference (#ManyToOne side) and it works but I wasn't be able to retrieve all needed information (for example #ManyToOne reference).
So i swapping #JsonBackReference on set structure and #JsonManagedReference on single object but I retrieve
No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: com.model.tablesField.TableUI["data"]->java.util.ArrayList[0]->com.domain.Car["carType"]->com.domain.CarType_$$_jvst744_f["handler"])
I tried also with #JsonIgnore on Set structure but it doesn't work for the same issues.
This is my spring configuration
private Properties getHibernateProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
// properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
properties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_FORMAT_SQL));
properties.put("hibernate.enable_lazy_load_no_trans",true);
return properties;
and this is part of one of my several entities:
/**
* Car generated by hbm2java
*/
#Entity
#Table(name = "car", catalog = "ATS")
public class Car implements java.io.Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer idCar;
#JsonManagedReference
private CarType carType;
#JsonManagedReference
private Fleet fleet;
private String id;
private int initialKm;
private String carChassis;
private String note;
#JsonBackReference
private Set<Acquisition> acquisitions = new HashSet<Acquisition>(0);
public Car() {
}
public Car(CarType carType, Fleet fleet, int initialKm, String carChassis) {
this.carType = carType;
this.fleet = fleet;
this.initialKm = initialKm;
this.carChassis = carChassis;
}
public Car(CarType carType, Fleet fleet, String id, int initialKm, String carChassis, String note,
Set<Acquisition> acquisitions) {
this.carType = carType;
this.fleet = fleet;
this.id = id;
this.initialKm = initialKm;
this.carChassis = carChassis;
this.note = note;
this.acquisitions = acquisitions;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id_car", unique = true, nullable = false)
public Integer getIdCar() {
return this.idCar;
}
public void setIdCar(Integer idCar) {
this.idCar = idCar;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_carType", nullable = false)
public CarType getCarType() {
return this.carType;
}
public void setCarType(CarType carType) {
this.carType = carType;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_fleet", nullable = false)
public Fleet getFleet() {
return this.fleet;
}
public void setFleet(Fleet fleet) {
this.fleet = fleet;
}
#Column(name = "id", length = 5)
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
#Column(name = "initialKm", nullable = false)
public int getInitialKm() {
return this.initialKm;
}
public void setInitialKm(int initialKm) {
this.initialKm = initialKm;
}
#Column(name = "carChassis", nullable = false, length = 20)
public String getCarChassis() {
return this.carChassis;
}
public void setCarChassis(String carChassis) {
this.carChassis = carChassis;
}
#Column(name = "note", length = 100)
public String getNote() {
return this.note;
}
public void setNote(String note) {
this.note = note;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "car")
public Set<Acquisition> getAcquisitions() {
return this.acquisitions;
}
public void setAcquisitions(Set<Acquisition> acquisitions) {
this.acquisitions = acquisitions;
}
}
one method that uses the query:
#Override
#RequestMapping(value = { "/cars/{idFleet}"}, method = RequestMethod.GET)
public #ResponseBody TableUI getCars(#PathVariable int idFleet) {
TableUI ajaxCall=new TableUI();
try {
ajaxCall.setData(fleetAndCarService.findCarsByIdFleet(idFleet));
return ajaxCall;
} catch (QueryException e) {
ErrorResponse errorResponse= ErrorResponseBuilder.buildErrorResponse(e);
LOG.error("Threw exception in FleetAndCarControllerImpl::addCar :" + errorResponse.getStacktrace());
return ajaxCall;
}
}
two class for the query:
public interface DefRdiRepository extends JpaRepository<DefRdi, Integer>{
//#Query("SELECT CASE WHEN COUNT(c) > 0 THEN true ELSE false END FROM DefRdi c WHERE c.parName = ?1 AND c.description= ?2")
//Boolean existsByParNameAndDescription(String parName, String description);
//Query method of spring, I put findBy and then the key of research
DefRdi findByParNameAndDescription(String parName, String description);
}
public interface CarRepository extends JpaRepository<Car, Integer>, CarRepositoryCustom {
//Query method of spring, I put findBy and then the key of research
List<Car> findByFleetIdFleet(int idFleet);
}
Where is my error? I don't want Set object but only the single reference. The problem is only when I serialize. Thanks
UPDATE:
I use #JSonIgnore on all set collectionts and Eager instead lazy ad all works fine, but is there a way to retrieve all the information only when I want, for example having two different query?
So it doesn't work
#Override
#Transactional
public List<Car> findByFleetIdFleet(int idFleet) {
List<Car> carList= carRepository.findByFleetIdFleet(idFleet);
for (Car car:carList){
Hibernate.initialize(car.getCarType());
Hibernate.initialize(car.getFleet());
}
return carList;
// return carRepository.findByFleetIdFleet(idFleet);
}
All collections need to be fetched eagerly when loading them from data base, in order to get serialized by Spring. Make sure you fetch them eagerly (e.g. FetchMode.JOIN). You could also swap #JsonManagedReference from wanted fields with #JsonIgnore to black listed fields, Spring automatically serialises every field without annotation.
Update:
Changing the data repository to something like that should work, I am not sure it compiles, but I think you will get the point:
#EntityGraph(value = "some.entity.graph", type = EntityGraph.EntityGraphType.FETCH)
#Query(
value = "SELECT c FROM Car c INNER JOIN FETCH c.acquisitions WHERE c.id = :idFleet"
)
public interface CarRepository extends JpaRepository<Car, Integer>, CarRepositoryCustom {
//Query method of spring, I put findBy and then the key of research
List<Car> findByFleetIdFleet(int idFleet);
}
For more information look at this post and read the official documentation.
Workaround:
There seems to be a workaround, however fetching those collections eager like shown above should have a positive performance impact, since there is no need for loading proxies afterwards. Also no open transactions are needed at controller level.

How to handle join query in Hibernate and Spring with annotations?

I am developing application using Spring and Hibernate with MySQL. I am new to Hibernate and did basic tasks...
Now I need to apply joins in select query to get data from multiple table using annotations. I have searched for it but still I didn't get any idea...
Here my database tables and bean classes :
Table 1: 'employee_info' ( id, empid, empname, doj and jobtitle )
Table 2: 'employee_login' ( username, password, status and empid )
And my bean classes are:
EmployeeInfoForm.java
#Entity()
#Table(name = "employee_info")
public class EmployeeInfoForm {
#Id
#GeneratedValue
#Column(name = "id", unique = true, nullable = true)
private int id;
#Column(name = "empId")
private int empId;
#Column(name = "empname")
private String empName;
#Column(name = "doj")
private Date empDoj;
#Column(name = "jobtitle")
private String empJobTitle;
public int getEmpId() {
return empId;
}
public void setEmpId(int empId) {
this.empId = empId;
}
public void setEmpDoj(Date empDoj) {
this.empDoj = empDoj;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Date getEmpDoj() {
return empDoj;
}
public void setEmp_Doj(Date empDoj) {
this.empDoj = empDoj;
}
public String getEmpJobTitle() {
return empJobTitle;
}
public void setEmpJobTitle(String empJobTitle) {
this.empJobTitle = empJobTitle;
}
}
EmployeeLoginForm.java
#Entity()
#Table(name = "employee_login")
public class EmployeeLoginForm {
#Id
#Column(name = "username")
private String empUserName;
#Column(name = "password")
private String empPassword;
#Column(name = "status")
private String empStatus;
#Column(name = "empid")
private int empId;
public String getEmpUserName() {
return empUserName;
}
public int getEmpId() {
return empId;
}
public void setEmpId(int empId) {
this.empId = empId;
}
public void setEmpUserName(String empUserName) {
this.empUserName = empUserName;
}
public String getEmpPassword() {
return empPassword;
}
public void setEmpPassword(String empPassword) {
this.empPassword = empPassword;
}
public String getEmpStatus() {
return empStatus;
}
public void setEmpStatus(String empStatus) {
this.empStatus = empStatus;
}
}
Requirement:
I want to select fields empid, empname, jobtitle from employee_info and field status from employee_login table when the empid matches on both table...
Please help me to complete my work...
Any suggestions and guidance are appreciated...
There is an association between EmployeeInfoForm and EmployeeLoginForm that I am not seeing in your code. Maybe there is an Employee class there? If that is the case then you need to add that. So let us assume that each employee has many forms. Then you will code the Employee side of the relationship like this:
public class Employee{
#OneToMany(cascade = CascadeType.ALL, mappedBy = "employee")
private Set<EmployeeLoginForm> loginForms = new HashSet<EmployeeLoginForm>();
...
}
And the Many side of the relationship in the EmployeeLoginForm class:
#ManyToOne
Employee employee;
This will create the table structure such that:
emploee = (id, etc ...)
employeelogin = (id, employee, ....)
Now, any time you need a list of the Logins of an Employee you get it from the Employee object without needing a Query.
Set<EmployeeLoginForm> logins = e.getLoginForms(); //where e is an employee object.
If you did want to query you can do
select o from EmployeeLoginForm o join o.employee
But that is unnecessary in this case.
You are thinking in database / pure SQL terms when you talk about performing joins with select statements. The power (and danger) of Hibernate is that it abstracts this away from you and lets you think in Object terms. What you need is a relationship between the 2 objects and then let Hibernate handle this relationship.
I recommend you spend some time reading this:
http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/associations.html
to get a better understanding of how Hibernate can help.
You can do the following using the Hibernate criteria projection:
public List extractEmployeeAttributes() {
log.debug("extractEmployeeAttributes");
try {
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
Criteria c1 = session.createCriteria(employee_info.class,emp_info);
Criteria c2 = session.createCriteria(employee_login.class,emp_log);
c1.setProjection(Projections.projectionList()
.add(Projections.property("empid"))
.add(Projections.property("empname"))
.add(Projections.property("jobtitle"))
.add(Projections.property("employee_info "))
.add(Restrictions.and(Property.eqName(emp_info.empId,emp_log.empId))
return c1.list();
} catch (RuntimeException re) {
log.error("extractEmployeeAttributes failed", re);
throw re;
}
}

Categories

Resources