Hibernate Annotation Query confusion - java

i have 4 tables in which purchaseOrder has relation ship with sullpier ,item,and ordertype.
reference key of all table to purchaseOrder is supplierIdfk,itemIdfk,orderTypeIdfk.
so my question how can i get record of purchaseOrder record who has suplliername="XXX" , suplliername is one of the column of supplier table.
i am using hibernate annotation and for backhand i am using mysql.
i have mapped all the entity with annotation.
Thanks For your Time.
My table looks like this
CREATE TABLE `purchaseorder` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`discount` double NOT NULL,
`finalAmount` double NOT NULL,
`remark` varchar(255) DEFAULT NULL,
`shipDate` datetime DEFAULT NULL,
`unitPrice` double NOT NULL,
`itemIdfk` int(11) DEFAULT NULL,
`orderIdfk` int(11) DEFAULT NULL,
`supplierIdfk` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `indexPurchaseOrderShipDate` (`shipDate`),
KEY `FKDFD4BAAD36B52348` (`itemIdfk`),
KEY `FKDFD4BAADFD3C54D4` (`orderIdfk`),
KEY `FKDFD4BAAD79028B3A` (`supplierIdfk`),
CONSTRAINT `FKDFD4BAAD36B52348` FOREIGN KEY (`itemIdfk`) REFERENCES `item` (`id`),
CONSTRAINT `FKDFD4BAAD79028B3A` FOREIGN KEY (`supplierIdfk`) REFERENCES `supplier` (`id`),
CONSTRAINT `FKDFD4BAADFD3C54D4` FOREIGN KEY (`orderIdfk`) REFERENCES `ordertype` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
my Entity code for purchaseOrder is like this.
package org.chillies.database;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import org.hibernate.annotations.Index;
#Entity
public class PurchaseOrder {
private int id;
private Date shipDate;
private double unitPrice;
private double discount;
private double finalAmount;
private String remark;
private OrderType orderType;
private Supplier supplier;
private Item item;
private static final String KeyOrderId = "orderIdfk";
private static final String KeySupplierId = "supplierIdfk";
private static final String KeyItemId = "itemIdfk";
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Index(name = "indexPurchaseOrderShipDate")
public Date getShipDate() {
return shipDate;
}
public void setShipDate(Date shipDate) {
this.shipDate = shipDate;
}
public double getUnitPrice() {
return unitPrice;
}
public void setUnitPrice(double unitPrice) {
this.unitPrice = unitPrice;
}
public double getDiscount() {
return discount;
}
public void setDiscount(double discount) {
this.discount = discount;
}
public double getFinalAmount() {
return finalAmount;
}
public void setFinalAmount(double finalAmount) {
this.finalAmount = finalAmount;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
#ManyToOne
#JoinColumn(name = KeyOrderId)
public OrderType getOrderType() {
return orderType;
}
public void setOrderType(OrderType orderType) {
this.orderType = orderType;
}
#ManyToOne
#JoinColumn(name = KeySupplierId)
public Supplier getSupplier() {
return supplier;
}
public void setSupplier(Supplier supplier) {
this.supplier = supplier;
}
#ManyToOne
#JoinColumn(name = KeyItemId)
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
}
actually i am using query code like this but it gives me error ...
public PurchaseOrder getPurchaseOrder(String supplierName) {
Session session = null;
PurchaseOrder purchaseOrder = new PurchaseOrder();
try {
session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Query query=session.createQuery("FROM PurchaseOrder WHERE PurchaseOrder.supplierIdfk=Supplier.id AND Supplier.name=?");
purchaseOrder = (PurchaseOrder)query.uniqueResult();
query.setString("Supplier.name",supplierName);
session.getTransaction().commit();
} catch (HibernateException e) {
if (session != null) {
session.getTransaction().rollback();
e.printStackTrace();
}
} finally {
if (session != null) {
session.close();
}
}
return purchaseOrder;
}
and my error code is like this
org.hibernate.QueryException: Unable to resolve path [PurchaseOrder.supplierIdfk], unexpected token [PurchaseOrder] [FROM org.chillies.database.PurchaseOrder WHERE PurchaseOrder.supplierIdfk=Supplier.id AND Supplier.name=?]
at org.hibernate.hql.ast.tree.IdentNode.resolveAsNakedComponentPropertyRefLHS(IdentNode.java:219)
at org.hibernate.hql.ast.tree.IdentNode.resolve(IdentNode.java:108)
at org.hibernate.hql.ast.tree.DotNode.resolveFirstChild(DotNode.java:175)
at org.hibernate.hql.ast.HqlSqlWalker.lookupProperty(HqlSqlWalker.java:550)
at org.hibernate.hql.antlr.HqlSqlBaseWalker.addrExpr(HqlSqlBaseWalker.java:4543)
at org.hibernate.hql.antlr.HqlSqlBaseWalker.expr(HqlSqlBaseWalker.java:1289)
at org.hibernate.hql.antlr.HqlSqlBaseWalker.exprOrSubquery(HqlSqlBaseWalker.java:4243)
at org.hibernate.hql.antlr.HqlSqlBaseWalker.comparisonExpr(HqlSqlBaseWalker.java:3722)
at org.hibernate.hql.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:1864)
at org.hibernate.hql.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:1789)
at org.hibernate.hql.antlr.HqlSqlBaseWalker.whereClause(HqlSqlBaseWalker.java:818)
at org.hibernate.hql.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:604)
at org.hibernate.hql.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:288)
at org.hibernate.hql.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:231)
at org.hibernate.hql.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:254)
at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:185)
at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:136)
at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:101)
at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:80)
at org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:94)
at org.hibernate.impl.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:156)
at org.hibernate.impl.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:135)
at org.hibernate.impl.SessionImpl.createQuery(SessionImpl.java:1651)
at org.chillies.dataaccesslayer.DataAccessLayer.getPurchaseOrder(DataAccessLayer.java:748)
at TestDataAccess.purchaseOrderDalTest(TestDataAccess.java:368)
at TestDataAccess.main(TestDataAccess.java:404)
Exception in thread "main" java.lang.NullPointerException
at TestDataAccess.purchaseOrderDalTest(TestDataAccess.java:370)
at TestDataAccess.main(TestDataAccess.java:404)

Assuming you have done all the mappings correctly, the query would be like this,
List<PurchaseOrder> purchaseOrders;
Session session = HibernateUtil.getSession();
Query query = session.createQuery("from PurchaseOrder po where po.supplierName = ?1");
query.setString(1, pass_your_supplier_name);
purchaseOrders = query.list();

Try
Query query=session.createQuery("select new fu.bar.PurchaseOrderDto(po.id, po.x, po.y, po.z) FROM PurchaseOrder po, Supplier sup WHERE po.supplier.id=sup.id AND sup.name=?");
or
Query query=session.createQuery("FROM PurchaseOrder po WHERE po.supplier.id=sup.id AND sup.name=?");
As I said in my comment:
If u are using HQL, you have to use the java-objects variables, not the database-fields.
I don't know if the second one is working, because the Supplier is not mentioned after "from". If it doesn't work, create 2 constructors in your entity: empty and one with the fields you need OR create a DTO with the fields you need. Then use the first query.
EDIT:
Second problem will be the "query.setString". It does not do what you want. Use setParameter instead:
[...]
Query query=session.createQuery("select new fu.bar.PurchaseOrderDto(po.id, po.x, po.y, po.z) FROM PurchaseOrder po, Supplier sup WHERE po.supplier.id=sup.id AND sup.name= :supName ");
query.setParameter("supName",supplierName);
purchaseOrder = (PurchaseOrder)query.uniqueResult();
session.getTransaction().commit();
[...]

Thanks for all the reply and your precious time.
I have found my answer.
i have build my query like this.
createQuery("FROM PurchaseOrder po LEFT JOIN FETCH po.supplier sup WHERE sup.name=:supName").setString("supName",suplierName);

Related

OneToOne with Composite Key

Trying to create a one to one on a table with a composite key.
I'm unable to get it to work and getting this error:
Error creating bean with name 'sessionFactory' defined in class path resource [applicationContext-dao.xml]: Invocation of init method failed; nested exception is org.hibernate.MappingException: broken column mapping for: compensation.id of: com.ciwise.model.Focus
Compensation.java:
package com.ciwise.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;
#Entity
#Table(name = "commissions")
public class Compensation implements Serializable {
private static final long serialVersionUID = 1L;
/**
* Composite key
*/
private CompensationPK compensationPK;
/**
* This year monthly net sales
*/
private double tYMonthlyNetSales;
/**
* Last year monthly net sales
*/
private double lYMonthlyNetSales;
/**
* This year YTD net sales
*/
private double tYYTDNetSales;
private Focus focus;
/**
* Getters and Setters
*/
#OneToOne( mappedBy = "compensation", fetch = FetchType.EAGER)
#JoinColumn(name = "FOCUS_ID")
public Focus getFocus() {
return focus;
}
public void setFocus(Focus focus) {
this.focus = focus;
}
#EmbeddedId
public CompensationPK getCompensationPK() {
return compensationPK;
}
public void setCompensationPK(CompensationPK compensationPK) {
this.compensationPK = compensationPK;
}
#Column(name = "TY_MONTHLY_NET_SALES")
public double gettYMonthlyNetSales() {
return tYMonthlyNetSales;
}
public void settYMonthlyNetSales(double tYMonthlyNetSales) {
this.tYMonthlyNetSales = tYMonthlyNetSales;
}
#Column(name = "LY_MONTHLY_NET_SALES")
public double getlYMonthlyNetSales() {
return lYMonthlyNetSales;
}
public void setlYMonthlyNetSales(double lYMonthlyNetSales) {
this.lYMonthlyNetSales = lYMonthlyNetSales;
}
#Column(name = "TY_YTD_NET_SALES")
public double gettYYTDNetSales() {
return tYYTDNetSales;
}
public void settYYTDNetSales(double tYYTDNetSales) {
this.tYYTDNetSales = tYYTDNetSales;
}
}
CompensationPK.java
package com.ciwise.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Embeddable;
#Embeddable
public class CompensationPK implements Serializable {
private String divisionId;
private String repId;
private int focusId;
private int repTypeId;
private int commissionYear;
private int commissionMonth;
#Column(name = "DIVISION_ID")
public String getDivisionId() {
return divisionId;
}
#Column(name = "REP_ID")
public String getRepId() {
return repId;
}
#Column(name = "FOCUS_ID")
public int getFocusId() {
return focusId;
}
#Column(name = "REPTYPE_ID")
public int getRepTypeId() {
return repTypeId;
}
#Column(name = "COMMISSION_YEAR")
public int getCommissionYear() {
return commissionYear;
}
#Column(name = "COMMISSION_MONTH")
public int getCommissionMonth() {
return commissionMonth;
}
public void setDivisionId(String divisionId) {
this.divisionId = divisionId;
}
public void setRepId(String repId) {
this.repId = repId;
}
public void setFocusId(int focusId) {
this.focusId = focusId;
}
public void setRepTypeId(int repTypeId) {
this.repTypeId = repTypeId;
}
public void setCommissionYear(int commissionYear) {
this.commissionYear = commissionYear;
}
public void setCommissionMonth(int commissionMonth) {
this.commissionMonth = commissionMonth;
}
#Override
public boolean equals(Object o) {
return false;
}
#Override
public int hashCode() {
return 0;
}
}
Focus.java:
package com.ciwise.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "CT_FOCUS")
public class Focus implements Serializable {
private int focusId;
private String focusDesc;
private String focusYN;
private Compensation compensation;
#OneToOne
#PrimaryKeyJoinColumn
public Compensation getCompensation() {
return compensation;
}
public void setCompensation(Compensation compensation) {
this.compensation = compensation;
}
public Focus() {
};
#Id
#Column(name = "FOCUS_ID")
public int getFocusId() {
return focusId;
}
public void setFocusId(int focusId) {
this.focusId = focusId;
}
#Column(name = "FOCUS_DESC", length = 16)
public String getFocusDesc() {
return focusDesc;
}
public void setFocusDesc(String focusDesc) {
this.focusDesc = focusDesc;
}
#Column(name = "FOCUS_YN", length = 1)
public String getFocusYN() {
return focusYN;
}
public void setFocusYN(String focusYN) {
this.focusYN = focusYN;
}
}
Since you used an embeddable type (CompositionPK) as your primary key for Composition entity, you should annotate the corresponding primary key field in your Composition entity with #EmbeddedId.
#EmbeddedId
private CompensationPK compensationPK;
On the Focus entity, you need not specify a #PrimaryKeyJoinColumn on the one-to-one mapping. It will just use the default join column names for the foreign keys.
So this code should be fine without the #PrimaryKeyJoinColumn:
#OneToOne
public Compensation getCompensation() {
return compensation;
}
This is a sample Hibernate generated schema based on your mappings (target DB is MySQL):
Hibernate:
create table CT_FOCUS (
FOCUS_ID integer not null,
FOCUS_DESC varchar(16),
FOCUS_YN varchar(1),
compensation_COMMISSION_MONTH integer,
compensation_COMMISSION_YEAR integer,
compensation_DIVISION_ID varchar(255),
compensation_FOCUS_ID integer,
compensation_REP_ID varchar(255),
compensation_REPTYPE_ID integer,
primary key (FOCUS_ID)
)
Hibernate:
create table commissions (
COMMISSION_MONTH integer not null,
COMMISSION_YEAR integer not null,
DIVISION_ID varchar(255) not null,
FOCUS_ID integer not null,
REP_ID varchar(255) not null,
REPTYPE_ID integer not null,
LY_MONTHLY_NET_SALES double precision,
TY_MONTHLY_NET_SALES double precision,
TY_YTD_NET_SALES double precision,
primary key (COMMISSION_MONTH, COMMISSION_YEAR, DIVISION_ID, FOCUS_ID, REP_ID, REPTYPE_ID)
)
Hibernate:
alter table CT_FOCUS
add constraint FK_d6d2c9n91dlw59uiuqswfueg5
foreign key (compensation_COMMISSION_MONTH, compensation_COMMISSION_YEAR, compensation_DIVISION_ID, compensation_FOCUS_ID, compensation_REP_ID, compensation_REPTYPE_ID)
references commissions (COMMISSION_MONTH, COMMISSION_YEAR, DIVISION_ID, FOCUS_ID, REP_ID, REPTYPE_ID)
#PrimaryKeyJoinColumn can be used on a #OneToOne mapping, if you want the primary keys of Focus entity to be referencing the primary keys of Commission entity. However, you already have defined a primary key for your Focus entity, which the focusId annotated by #Id. So there's no need to specify a #PrimaryKeyJoinColumn.

JPA find() does not load Entity #Id

I'm starting to use JPA with the OpenJPA API, and i'm having a problem with the find().
Here are the tables:
CREATE TABLE compania (
ID int(11) NOT NULL,
NOMBRE varchar(45) DEFAULT NULL,
PRIMARY KEY (ID)
)
CREATE TABLE modelo (
ID int(11) NOT NULL,
ID_COMPANIA int(11) DEFAULT NULL,
NOMBRE_MODELO varchar(45) DEFAULT NULL,
PRIMARY KEY (ID),
KEY MODELO_COMPANIA_FK_idx (ID_COMPANIA),
CONSTRAINT MODELO_COMPANIA_FK FOREIGN KEY (ID_COMPANIA) REFERENCES compania (ID)
)
and here are my Entities:
#Entity
public class Compania extends EntityJPA{
private static final long serialVersionUID = 1L;
#Id
private int id;
#Column
private String nombre;
#OneToMany(mappedBy="compania",cascade={CascadeType.ALL})
#JoinColumn(name="ID_COMPANIA", nullable=false)
private List<Modelo> listaModelos;
public Compania() {
}
public int getId() {
return id;
}
public void setId(int idCompania) {
this.id = idCompania;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombreCompania) {
this.nombre = nombreCompania;
}
public List<Modelo> getListaModelos() {
return listaModelos;
}
public void setListaModelos(List<Modelo> listaModelos) {
this.listaModelos = listaModelos;
}
}
#Entity
public class Modelo extends EntityJPA{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#Column(name="NOMBRE_MODELO")
private String nombreModelo;
#ManyToOne
#JoinColumn(name="ID_COMPANIA", referencedColumnName="ID")
private Compania compania;
public Modelo() {
}
public Compania getCompania() {
return compania;
}
public void setCompania(Compania compania) {
this.compania = compania;
}
public int getId() {
return id;
}
public void setId(int idModelo) {
this.id = idModelo;
}
public String getNombre() {
return nombreModelo;
}
public void setNombre(String nombreModelo) {
this.nombreModelo = nombreModelo;
}
}
At the moment I make the
Compania cia = getEntityManager().find(Compania.class, idCompania);
the cia object does not have the value of the #Id attribute, it has the value of nombre but not of id. I mean:
cia.getId() = 0
and it must be 1 or 2 , etc. Not 0.
Thank you very much for your help.
I do not have the code to persist because It was already persisted.
the code for the find is
public static Compania findCompania(int idCompania){
try {
Compania cia = getEntityManager().find(Compania.class, idCompania);
return cia;
} finally {
closeEntityManager();
}
}
And if I activate the log, this is the select it shows:
482 testMySql TRACE [http-bio-8080-exec-5] openjpa.jdbc.SQL - <t 1228180882, conn 1699837157> executing prepstmnt 2127861376 SELECT t0.nombre FROM Compania t0 WHERE t0.id = ? [params=(int) 1]
497 testMySql TRACE [http-bio-8080-exec-5] openjpa.jdbc.SQL - <t 1228180882, conn 1699837157> [15 ms] spent
As you can see, there is no t0.id in the select.
Thanks for your help.
Primary Key (ID) not retrieved (?) from database using OpenJPA
Duplicate.... the net of the post is that you need to use a different enhancement method.
If you don't specifically set the value for the #Id attribute you have to declare it with #GeneratedValueso that it's automatically incremented.

one to many hibernate

Hi I am trying to do one to many insert but I am having problems.
I have two tables:
CREATE TABLE users_app (
user_id int UNSIGNED NOT NULL AUTO_INCREMENT,
user_number varchar(45) NOT NULL default '0',
user_password varchar(45) NOT NULL default '0',
os int(1) unsigned NOT NULL,
token varchar(500) NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8;
CREATE TABLE user_app_devices(
id int AUTO_INCREMENT PRIMARY KEY,
user_id int UNSIGNED NOT NULL,
device_name varchar(45) NOT NULL,
FOREIGN KEY (user_id) REFERENCES users_app (user_id)
)ENGINE=InnoDB CHARSET=utf8;
My classes:
#Entity
#Table(name="user_app_devices")
public class UserAppDevice implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private int id;
#Column(name="device_name")
private String deviceName;
//bi-directional many-to-one association to UsersApp
#ManyToOne
#JoinColumn(name="user_id")
private UsersApp usersApp;
public UserAppDevice() {
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getDeviceName() {
return this.deviceName;
}
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
public UsersApp getUsersApp() {
return this.usersApp;
}
public void setUsersApp(UsersApp usersApp) {
this.usersApp = usersApp;
}
}
#Entity
#Table(name="users_app")
public class UsersApp implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="user_id")
private int userId;
private int os;
private String token;
#Column(name="user_number")
private String userNumber;
#Column(name="user_password")
private String userPassword;
//bi-directional many-to-one association to UserAppDevice
#OneToMany(mappedBy="usersApp")
private List<UserAppDevice> userAppDevices;
public UsersApp() {
}
public int getUserId() {
return this.userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public int getOs() {
return this.os;
}
public void setOs(int os) {
this.os = os;
}
public String getToken() {
return this.token;
}
public void setToken(String token) {
this.token = token;
}
public String getUserNumber() {
return this.userNumber;
}
public void setUserNumber(String userNumber) {
this.userNumber = userNumber;
}
public String getUserPassword() {
return this.userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public List<UserAppDevice> getUserAppDevices() {
return this.userAppDevices;
}
public void setUserAppDevices(List<UserAppDevice> userAppDevices) {
this.userAppDevices = userAppDevices;
}
public UsersApp(int os, String token, String userNumber, String userPassword) {
this.os = os;
this.token = token;
this.userNumber = userNumber;
this.userPassword = userPassword;
}
I want to add new user with device
I try this code:
Session session = (Session) em.getDelegate();
session.beginTransaction();
UsersApp user = new UsersApp(os, token, userNumber, userPassword);
session.save(user);
UserAppDevice ud = new UserAppDevice();
ud.setUsersApp(user);
ud.setDeviceName(device);
session.save(ud);
session.getTransaction().commit();
but I am facing exception:
13:16:48,516 WARN [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http--0.0.0.0-8080-3) SQL Error: 1452, SQLState: 23000
13:16:48,517 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http--0.0.0.0-8080-3) Cannot add or update a child row: a foreign key constraint fails (`application`.`user_a
pp_devices`, CONSTRAINT `user_app_devices_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users_app` (`user_id`))
13:16:48,520 ERROR [org.jboss.as.ejb3.tx.CMTTxInterceptor] (http--0.0.0.0-8080-3) javax.ejb.EJBTransactionRolledbackException: Cannot add or update a child row: a foreign key const
raint fails (`application`.`user_app_devices`, CONSTRAINT `user_app_devices_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users_app` (`user_id`))
13:16:48,524 ERROR [org.jboss.ejb3.invocation] (http--0.0.0.0-8080-3) JBAS014134: EJB Invocation failed on component DeviceRegisterDAOImpl for method public abstract void com.break
id.ejb.model.DeviceRegisterDAO.add(int,java.lang.String,java.lang.String,java.lang.String,java.lang.String): javax.ejb.EJBTransactionRolledbackException: Cannot add or update a chi
ld row: a foreign key constraint fails (`application`.`user_app_devices`, CONSTRAINT `user_app_devices_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users_app` (`user_id`))
at org.jboss.as.ejb3.tx.CMTTxInterceptor.handleInCallerTx(CMTTxInterceptor.java:139) [jboss-as-ejb3-7.1.1.Final.jar:7.1.1.Final]
at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInCallerTx(CMTTxInterceptor.java:204) [jboss-as-ejb3-7.1.1.Final.jar:7.1.1.Final]
at org.jboss.as.ejb3.tx.CMTTxInterceptor.required(CMTTxInterceptor.java:306) [jboss-as-ejb3-7.1.1.Final.jar:7.1.1.Final]
at org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:190) [jboss-as-ejb3-7.1.1.Final.jar:7.1.1.Final]
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.1.Final.jar:1.1.1.Final]
at org.jboss.as.ejb3.remote.EJBRemoteTransactionPropagatingInterceptor.processInvocation(EJBRemoteTransactionPropagatingInterceptor.java:80) [jboss-as-ejb3-7.1.1.Final.jar:
7.1.1.Final]
What am I missing ?
You haven't told Hibernate that the ID of UserApp was generated automatically by the database:
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name="user_id")
private int userId;
(and do the same for the other entity)
Since your are using bidirectional, change your client code as below.
Session session = (Session) em.getDelegate();
session.beginTransaction();
UserAppDevice ud = new UserAppDevice();
ud.setDeviceName(device);
UsersApp user = new UsersApp(os, token, userNumber, userPassword);
user.setUserAppDevices(new ArrayList<UserAppDevice>())
user.getUserAppDevices().add(ud);
session.save(user);
session.getTransaction().commit();
As mentioned by JB Nizet, you're missing the autogenerated strategy.
An alternative would be to use UUID as your id column and create the values yourself with
#Id
private UUID id = UUID.randomUUID();
Also, don't forget to set equals/hashCode to use the id field as discussed to death in The JPA hashCode() / equals() dilemma
Incidentally, why are you using Session (hibernate specific) instead of sticking to JPA's API?

Hibernate: Transfer seeming n:n mapping in Database to #OneToMany in Hibernate with additional condition

I have a Database with a Mapping between applications and application_descriptions. Every application could have more than one description (mapped by column product_id). Column product_id in table applications can have duplicate values, but combinations of column product_id and column wrapping_version are unique. So the descriptions should only map to the application with highest version.
I have worked out a #OneToMany mapping in table application to get all descriptions. In descriptions I only get the String of product_id. That’s not optimal, but it doesn’t work to map it like in alternative a).
So the solution I have made worked fine for reading data from database, but when I try to update an application to database I get (only sometimes) following error:
Hibernate:
/* update
com.twistbox.iwp.dao.Application */ update
applications
set
created=?,
design_id=?,
message=?,
product_id=?,
product_title=?,
retailer_id=?,
state=?,
tbyb_playduration=?,
tbyb_startups=?,
wrapping_security_layer=?,
wrapping_version=?
where
id=?
Hibernate:
/* delete one-to-many com.twistbox.iwp.dao.Application.applicationDescriptions */ update
application_descriptions
set
product_id=null
where
product_id=?
104330 [http-8080-1] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 1048, SQLState: 23000
104330 [http-8080-1] ERROR org.hibernate.util.JDBCExceptionReporter - Column 'product_id' cannot be null
I have tried
1. to set the mapped description set to null before updating
2. set to a new empty HashSet Object before updating
3. let the mapped object like I get it from database
On default hibernate shouldn’t cascade on update and I haven’t found a way to stop doing it (last try was #OneToMany(cascade = {})). I have also tried in both tables true and false values for:
1. attribute null-able
2. updateable
3. insertable
Some of them worked for the application I got the error, but then I get same error for other applications witch only works if I remove the attributes again. Any ideas what to do?
My code (only important getter and setter, all other removed for better overview):
#Entity
#Table (name = "applications")
#FilterDef(name = "versionFilter")
public class Application implements Comparable<Application>, Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private long id;
private Retailer retailerId;
private long designId;
private String productId;
private String productTitle;
private int tbybPlayDuration;
private int tbybStartups;
private int wrappingSecurityLayer;
private int wrappingVersion;
private ApplicationStatus status;
private String message;
private Timestamp created;
private Set<ApplicationDescription> applicationDescriptions = new HashSet<ApplicationDescription>();
private Set<PricingApplicationMapping> pricingApplication = new HashSet<PricingApplicationMapping>();
public Application() {
}
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#GenericGenerator(name="increment", strategy="increment")
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#Column(name="product_id")
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
#OneToMany(cascade = {})
#JoinColumn(name="product_id", referencedColumnName="product_id")
#Filter(name = "versionFilter", condition = "wrapping_version =select max(A.wrapping_version) from application A where A.product_id= product_id")
public Set<ApplicationDescription> getApplicationDescriptions() {
return applicationDescriptions;
}
public void setApplicationDescriptions(
Set<ApplicationDescription> applicationDescriptions) {
this.applicationDescriptions = applicationDescriptions;
}
#Override
public int compareTo(Application o) {
return this.getProductTitle().compareToIgnoreCase(o.getProductTitle());
}
}
#Entity
#Table (name = "application_descriptions")
#FilterDef(name = "paMapping")
public class ApplicationDescription implements Comparable<ApplicationDescription>, Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private long id;
private String productId;
// private Application application;
// private String countryCode;
private Territory territory;
private String name;
private String description;
private String termsAndConditions;
public ApplicationDescription() {
}
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#GenericGenerator(name="increment", strategy="increment")
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
// #ManyToOne
// #JoinColumn(name="product_id")
// public Application getApplication() {
// return application;
// }
//
// public void setApplication(Application application) {
// this.application = application;
// }
#Column(name="product_id")
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
#Column(name="name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Column(name="description")
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#Column(name="terms_and_conditions")
public String getTermsAndConditions() {
if (this.termsAndConditions != null && !this.termsAndConditions.equals("") && !this.termsAndConditions.toLowerCase().equals("null"))
return this.termsAndConditions;
return "default";
}
public void setTermsAndConditions(String termsAndConditions) {
this.termsAndConditions = termsAndConditions;
}
#JoinColumn(name="country_code")
#OneToOne
public Territory getTerritory() {
return territory;
}
public void setTerritory(Territory territory) {
this.territory = territory;
}
#Override
public int compareTo(ApplicationDescription o) {
return this.getTerritory().getCountryCode().compareToIgnoreCase(o.getTerritory().getCountryCode());
}
}
Alternative for product_id in application_descriptions a):
#ManyToOne
#JoinColumn(name="product_id")
public Application getApplication() {
return application;
}
Error Message:
Hibernate:
/* load one-to-many com.twistbox.iwp.dao.Application.applicationDescriptions */ select
applicatio0_.product_id as product5_0_2_,
applicatio0_.id as id2_,
applicatio0_.id as id4_1_,
applicatio0_.product_id as product5_4_1_,
applicatio0_.description as descript2_4_1_,
applicatio0_.name as name4_1_,
applicatio0_.terms_and_conditions as terms4_4_1_,
applicatio0_.country_code as country6_4_1_,
territory1_.country_code as country1_8_0_,
territory1_.currency as currency8_0_,
territory1_.name as name8_0_,
territory1_.terms_and_conditions as terms4_8_0_
from
application_descriptions applicatio0_
left outer join
territories territory1_
on applicatio0_.country_code=territory1_.country_code
where
applicatio0_.product_id=?
180684 [http-8080-1] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 0, SQLState: S1009
180684 [http-8080-1] ERROR org.hibernate.util.JDBCExceptionReporter - Invalid value for getLong() - 'para'
SQL generating tables:
CREATE TABLE IF NOT EXISTS `applications` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`retailer_id` int(10) unsigned NOT NULL,
`design_id` int(10) unsigned NOT NULL,
`product_id` varchar(150) NOT NULL,
`product_title` varchar(150) NOT NULL,
`tbyb_playduration` int(10) NOT NULL,
`tbyb_startups` int(10) NOT NULL,
`wrapping_security_layer` int(10) unsigned NOT NULL DEFAULT '1',
`wrapping_version` int(10) unsigned NOT NULL DEFAULT '1',
`state` enum('WAITING','RUNNING','DONE','FAILED') NOT NULL DEFAULT 'WAITING',
`message` varchar(250) DEFAULT NULL,
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `product_id_wrapping_version` (`product_id`,`wrapping_version`),
KEY `FK_applications_retailers` (`retailer_id`),
KEY `FK_applications_custom_designs` (`design_id`),
KEY `product_id` (`product_id`),
CONSTRAINT `FK_applications_custom_designs` FOREIGN KEY (`design_id`) REFERENCES `custom_designs` (`id`),
CONSTRAINT `FK_applications_retailers` FOREIGN KEY (`retailer_id`) REFERENCES `retailers` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `application_descriptions` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`product_id` varchar(150) NOT NULL,
`country_code` varchar(5) NOT NULL,
`name` varchar(150) NOT NULL,
`description` varchar(500) NOT NULL,
`terms_and_conditions` text,
PRIMARY KEY (`id`),
UNIQUE KEY `product_id_county_code` (`product_id`,`country_code`),
KEY `FK_application_descriptions_applications` (`product_id`),
KEY `FK_application_descriptions_territories` (`country_code`),
CONSTRAINT `FK_application_descriptions_territories` FOREIGN KEY (`country_code`) REFERENCES `territories` (`country_code`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Application update:
public static long updateApplication(Application application){
SessionFactory sf = HibernateUtil.getSessionFactory();
Session session = null;
try{
session = sf.openSession();
session.beginTransaction();
session.saveOrUpdate(application);
session.getTransaction().commit();
}
catch(HibernateException he){
logger.severe("Error updating application! " + he.getMessage() + " " + he.getStackTrace());
return -1;
}
catch(Exception e){
logger.severe("Error updating application! " + e.getMessage() + " " + e.getStackTrace());
return -1;
}
finally{
session.close();
}
return application.getId();
}

How to Represent Composite keys in Hibernate using Annotations?

So I reverse engineered some tables from my db and when I try to save my object to the db I get the following error:
Initial SessionFactory creation failed.org.hibernate.AnnotationException: A Foreign key refering com.mycode.Block from com.mycode.Account has the wrong number of column. should be 2
Exception in thread "main" java.lang.ExceptionInInitializerError
The Domain objects Are Block which contains a number of Account Objects:
#OneToMany(fetch = FetchType.LAZY, mappedBy = "Block")
public Set<EAccount> getAccounts() {
return this.Accounts;
}
Account has a Composite key of Id and Role. This has been setup in a seperate Class:
#Embeddable
public class BlockAccountId implements java.io.Serializable {
private long blockOid;
private String accountRole;
public BlockAccountId() {
}
public BlockAccountId(long blockOid, String accountRole) {
this.blockOid = blockOid;
this.accountRole = accountRole;
}
#Column(name = "BLOCK_OID", nullable = false)
public long getBlockOid() {
return this.blockOid;
}
public void setBlockOid(long blockOid) {
this.blockOid = blockOid;
}
#Column(name = "ACCOUNT_ROLE", nullable = false, length = 10)
public String getAccountRole() {
return this.accountRole;
}
public void setAccountRole(String accountRole) {
this.accountRole = accountRole;
}
So I want to know. How can I Link the tables Block and account on blockOid but still ensure the account table has both blockOid and accountRole as a composite key.
Any examples would be greatly appreciated!
N.B this is a Block (One) to Account (Many) relationship.
Thanks
The easiest is to place your association directly in the embedded id component.
Hibernate reference documentation
Section 5.1.2.1.1. id as a property using a component type ()
Example (Only write the important getter() and setter())
#Entity
public class Block {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="BLOCK_OID")
long blockOid;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "id.block", cascade=CascadeType.ALL)
Set<Account> accounts = new HashSet<Account>();
}
#Entity
public class Account {
#EmbeddedId BlockAccountId id;
public Account()
{
this.id = new BlockAccountId();
}
public void setBlock(Block pBlock) {
this.id.setBlock(pBlock);
}
public Block getBlock() {
return this.id.getBlock();
}
public String getAccountRole() {
return this.id.getAccountRole();
}
public void setAccountRole(String accountRole) {
this.id.setAccountRole(accountRole);
}
}
#Embeddable
public class BlockAccountId implements java.io.Serializable {
#ManyToOne(optional = false)
private Block block;
#Column(name = "ACCOUNT_ROLE", nullable = false, length = 10)
private String accountRole;
public BlockAccountId() {
}
//Implement equals and hashcode
}
The corresponding database table are :
CREATE TABLE block (
BLOCK_OID bigint(20) NOT NULL auto_increment,
PRIMARY KEY (`BLOCK_OID`)
)
CREATE TABLE account (
ACCOUNT_ROLE varchar(10) NOT NULL,
block_BLOCK_OID bigint(20) NOT NULL,
PRIMARY KEY (`ACCOUNT_ROLE`,`block_BLOCK_OID`),
KEY `FK_block_OID` (`block_BLOCK_OID`),
CONSTRAINT `FK_block_OID` FOREIGN KEY (`block_BLOCK_OID`) REFERENCES `block` (`BLOCK_OID`)
)
based on hibernate documentation here's the link
based on it you can do the following :
#Entity
public class Account {
#EmbeddedId BlockAccountId id;
#MapsId(value = "blockOid")
#ManyToOne
private Block block;
public Account()
{
this.id = new BlockAccountId();
}
public void setBlock(Block pBlock) {
this.block = pBlock;
}
public Block getBlock() {
return this.block;
}
public String getAccountRole() {
return this.id.getAccountRole();
}
public void setAccountRole(String accountRole) {
this.id.setAccountRole(accountRole);
}
}

Categories

Resources