I can't get cascade to work on an entity,Hibernate - java

I have a entity that has two Many-To-One relationships, and one of them cascades on save just fine and the other one returns:
Exception in thread "main" org.hibernate.TransientObjectException: object references an
unsaved transient instance - save the transient instance before flushing : dto.publicSchema.Pessoas
Here is the code of the entity that works:
#Entity
#Table(name="`Doc_tipo`", schema="public")
public class Doc_tipo implements Serializable {
private static final long serialVersionUID = 1859372890916956036L;
#Id
#Column(nullable=false)
private int tp_doc;
#Column(nullable=false,columnDefinition="CHAR(255)")
private String descricao;
#Column(nullable=false,columnDefinition="CHAR(255)")
private String tp_emissor;
//getters and setters
}
And here is the code of the entity that will not allow cascade:
#Entity
#Table(name="`Pessoas`", schema="public")
public class Pessoas implements Serializable {
private static final long serialVersionUID = 8292302132119274975L;
#Id #GeneratedValue
#Column(nullable=false,columnDefinition="serial NOT NULL")
private int seq_pessoa;
static Date padrao_dt_criacao = new Date();
#Column(nullable=false, columnDefinition="date NOT NULL")
private Date dt_criacao = padrao_dt_criacao;
#Column(columnDefinition="CHAR(255)")
private String nome;
#Column(columnDefinition="CHAR(1) NULL")
private char tp_pessoa;
#Column(columnDefinition="CHAR(255)")
private String fantasia;
#Column(columnDefinition="VARCHAR(25)")
private String idioma;
#Column(columnDefinition="VARCHAR(25)")
private String login;
#Column(columnDefinition="VARCHAR(25)")
private String senha;
static Date padrao_dt_i = new Date();
#Column(nullable=false, columnDefinition="date NOT NULL")
private Date dt_i = padrao_dt_i;
//Pessoa está ativa para o sitema se este campo estiver em branco
#Column(columnDefinition="date")
private Date dt_f;
#Column(columnDefinition="oid")
private int foto;
//getters and setters
}
And here is the class that has relationships Many-To-One with the two above
but cascade will only work on the first one:
#Entity
#Table(name="`Documentos`", schema="public")
public class Documentos implements Serializable {
private static final long serialVersionUID = -4874330647877687810L;
#Id
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="seq_pessoa",columnDefinition="integer",referencedColumnName="seq_pessoa",nullable=false)
private Pessoas seq_pessoa;
#Id #GeneratedValue
#Column(nullable=false,columnDefinition="serial NOT NULL")
private int cd_doc;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="tp_doc",referencedColumnName="tp_doc",nullable=false)
private Doc_tipo tp_doc;
#Column(nullable=false)
private int tp_emissor;
#Column(nullable=false,columnDefinition="CHAR(2) NOT NULL DEFAULT 'DF'::bpchar")
private String tp_emissor_uf="DF";
#Column(columnDefinition="CHAR(5)")
private String alfa_doc;
#Column(nullable=false,columnDefinition="CHAR(20)")
private String nr_doc;
//Data de validade do documento
#Column(columnDefinition="date")
private Date dt_f_valid;
#Transient
transient static Date padrao_dt_i = new Date();
#Column(columnDefinition="date DEFAULT now()")
private Date dt_i = padrao_dt_i;
#Column(columnDefinition="date")
private Date dt_f;
//getters and setters
}
When I go to save a Documentos object hibernate inserts the Doc_tipo in to its table
as its supposed to, and instead of inserting the Pessoa object as well throws me that exception.
Here is the class that manipulates the session(it's just for tests):
public class Hibernate {
public static SessionFactory getSessionFactory() {
SessionFactory sessionFactory = null;
try {
Configuration configuration = new Configuration();
configuration.configure();
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(
configuration.getProperties()).buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (HibernateException hbe) {
hbe.printStackTrace();
}
return sessionFactory;
}
public static void main(String[] args) {
SessionFactory sessionFactory = getSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
Pessoas a = new Pessoas();
a.setDt_criacao(new Date());
a.setDt_f(new Date());
a.setDt_i(new Date());
a.setFantasia("teste");
a.setFoto(12);
a.setIdioma("aa");
a.setLogin("aa");
a.setNome("aa");
a.setSenha("a");
a.setTp_pessoa('H');
Doc_tipo b = new Doc_tipo();
b.setDescricao("aa");
b.setTp_doc(5);
b.setTp_emissor("aaa");
Documentos c = new Documentos();
c.setAlfa_doc("aaa");
c.setDt_f(new Date());
c.setDt_f_valid(new Date());
c.setDt_i(new Date());
c.setNr_doc("aa");
c.setSeq_pessoa(a);
c.setTp_doc(b);
c.setTp_emissor(1);
c.setTp_emissor_uf("aa");
//session.save(a);
session.save(c);
session.getTransaction().commit();
session.close();
}
}
If i remove the comment on the save() Pessoas object, everything works fine, but i shouldn't have to do that, the same exception happens when i try to cascade save in another
entity that has a Many-To-One relationship with Pessoas too.

Documentos references Pessoas with primary key (Pessoas.seq_pessoa) which is only created after it has been saved/flushed to database as Pessoas uses serial. So there is nothing to reference with before save/persist actually happens.
Also, you shouldn't use multiple #Id annotations to define composite identity unless you are also defining #IdClass that holds aforementioned #Id fields. Or you could you #EmbeddedId annotation as well. JPA supports two different approaches for compound PKs. In each case there must be a PK class that includes the fields.
A) Multiple #Id fields/attributes on the entity. Names and types of fields in the entity must match those in the PK class. Must also have an #IdClass annotation on the class. Ex:
public class EmpPK {
int id;
String name;
...
}
#Entity
#IdClass(EmpPK.class)
public class Employee {
#Id int id;
#Id String name;
...
}
B) Embed an attribute of the PK class in the entity. In this case the attribute is marked with #EmbeddedId and the PK class must be annotated with #Embeddable. Ex:
#Embeddable
public class EmpPK {
int id;
String name;
...
}
#Entity
public class Employee {
#EmbeddedId EmpPK empId;
...
}

Related

Error message when persisting entity with EmbbededID in Many To One relationship

I'm developing a project in JSF, and I'm trying to persist this Entity below, but I'm receiving a error message. Before I created the relationship, the Conta class was persisting correctly, but with the Many To One with Transacao, I can't.
This is the Transacao class:
#Id
#GeneratedValue
private long id;
private Conta contaOrigem;
private String agenciaDestino;
private String contaDestino;
private String cpfDestino;
...
This is the Conta class:
public class Conta {
#EmbeddedId
private DadosConta contaUsuario = new DadosConta();
#NotEmpty(message="Senha não pode estar em branco")
private String senha;
#NotEmpty(message="Selecione uma opção")
private String tipoConta;
private double saldo;
private Usuario usuario = new Usuario();
#OneToMany(mappedBy="contaOrigem", fetch = FetchType.LAZY)
private List<Transacao> transacoes = new ArrayList<>();
...
And the DadosConta (Embedded ID class):
#Embeddable
public class DadosConta implements Serializable {
private static final long serialVersionUID = -7021727065659352073L;
#NotEmpty
private String agencia;
#NotEmpty
private String conta;
...
And finally, this is the error:
Foreign key (FK_8k5jlptboiq6xm4oopg9jnh2l:Transacao [contaOrigem])) must have same number of columns as the referenced primary key (conta [agencia,conta])
I know that the error message is "explicit", but I don't know how can I persist this Many to One relationship with EmbeddedId, is there any workaround?
Thanks a lot.
Try this in your Transacao class to complete the bi-directional join.
#ManyToOne
#JoinColumns({#JoinColumn(name = "agencia"), #JoinColumn(name = "conta")})
private Conta contaOrigem;

Add multiple Example in criteria (Hibernate)

SchoolViewModel.java
public class SchoolViewModel {
private String state;
private String city;
private String instituteType;
//getter and setter
}
InstituteType.java
#Entity
#Table(name="REF_INSTITUTE_TYPE")
public class InstituteType implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#Column(name="ID")
private Integer id;
#Column(name="INSTITUTE_TYPE")
private String instituteType;
public Integer getId() {
return id;
}
#ManyToMany(mappedBy="instituteType")
private Set<SchoolDetail> schoolDetail =new HashSet<SchoolDetail>();
//getter and setter
}
Board.java
#Entity
#Table(name="REF_BOARD")
public class Board implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#Column(name="ID")
private Integer id;
#Column(name="BAORD")
private String board;
#ManyToMany(mappedBy="board")
private Set<SchoolDetail> schoolDetail =new HashSet<SchoolDetail>();
//getter and setter
}
SchoolDetail.java
#Entity
#Table(name="SCHOOL_DETAIL")
public class SchoolDetail implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#Column(name="id")
private int id;
#Column(name="name")
private String name;
#Column(name="state")
private String state;
#Column(name="city")
private String city;
#ManyToMany
#JoinTable(name="SCHOOL_INSTITUTE_TYPE",
joinColumns={#JoinColumn(name="SCHOOL_ID")},
inverseJoinColumns={#JoinColumn(name="INSTITUTE_TYPE_ID")}
)
private Set<InstituteType> instituteType=new HashSet<InstituteType>();
#ManyToMany
#JoinTable(name="SCHOOL_BOARD",
joinColumns={#JoinColumn(name="SCHOOL_ID")},
inverseJoinColumns={#JoinColumn(name="BOARD_ID")}
)
private Set<Board> board=new HashSet<Board>();
//getter and setter
}
Main.java
public class SchoolBoard {
public static void main(String[] args) {
Configuration cfg=new Configuration();
cfg.configure("hibernate.cfg.xml");
SessionFactory sessionFactory=cfg.buildSessionFactory();
Session session=sessionFactory.openSession();
try{
SchoolViewModel svm=new SchoolViewModel();
svm.setState("Maharastra");
svm.setCity("Pune");
svm.setInstituteType("college");
SchoolDetail school=new SchoolDetail();
school.setState(svm.getState());
school.setCity(svm.getCity());
InstituteType instituteType=new InstituteType();
instituteType.setInstituteType(svm.getInstituteType());
Board board=new Board();
board.setBoard("STATE");
Example schoolExample=Example.create(school).ignoreCase().enableLike().excludeZeroes();
Example instituteTypeExample=Example.create(instituteType).ignoreCase().enableLike().excludeZeroes();
Example boardExample=Example.create(board).ignoreCase().enableLike().excludeZeroes();
Criteria criteria=session.createCriteria(SchoolDetail.class,"schoolDetail");
criteria.createAlias("schoolDetail.instituteType", "instituteType");
criteria.createAlias("schoolDetail.board", "board");
criteria.add(schoolExample);
criteria.add(instituteTypeExample);
criteria.add(boardExample);
Line - 48 List<SchoolDetail> schoolList=criteria.list();
}finally{
session.close();
sessionFactory.close();
}
}
}
Exception is :
Exception in thread "main" org.hibernate.property.access.spi.PropertyAccessException: Error accessing field [private java.util.Set<com.mypack.model.Board> com.mypack.model.SchoolDetail.board] by reflection for persistent property [com.mypack.model.SchoolDetail#board] : com.mypack.model.InstituteType#f555e7
at org.hibernate.property.access.spi.GetterFieldImpl.get(GetterFieldImpl.java:71)
at org.hibernate.tuple.entity.AbstractEntityTuplizer.getPropertyValues(AbstractEntityTuplizer.java:506)
at org.hibernate.tuple.entity.PojoEntityTuplizer.getPropertyValues(PojoEntityTuplizer.java:215)
at org.hibernate.persister.entity.AbstractEntityPersister.getPropertyValues(AbstractEntityPersister.java:4626)
at org.hibernate.criterion.Example.toSqlString(Example.java:190)
at org.hibernate.loader.criteria.CriteriaQueryTranslator.getWhereCondition(CriteriaQueryTranslator.java:400)
at org.hibernate.loader.criteria.CriteriaJoinWalker.<init>(CriteriaJoinWalker.java:106)
at org.hibernate.loader.criteria.CriteriaJoinWalker.<init>(CriteriaJoinWalker.java:75)
at org.hibernate.loader.criteria.CriteriaLoader.<init>(CriteriaLoader.java:80)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1849)
at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:365)
at com.mypack.dao.SchoolBoard.main(SchoolBoard.java:48)
Caused by: java.lang.IllegalArgumentException: Can not set java.util.Set field com.mypack.model.SchoolDetail.board to com.mypack.model.InstituteType
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36)
at java.lang.reflect.Field.get(Field.java:387)
at org.hibernate.property.access.spi.GetterFieldImpl.get(GetterFieldImpl.java:67)
... 11 more
Description : SchoolViewModel is pojo class which will carry data from front end. The screen is Search screen and contains Refine your search just like any e-commerce website where you can filter or narrow down your search. Based on user selection database will retrieve data from database. For this I have implement query by example in hibernate. But while multiple examples in criteria it throws exception.

hibernate filter not working in the case of session.get() but working in the case of session.createQuery()

I am using hibernate 4. I am writing a filter. The strange thing I noticed is the filter is not getting applied if I use session.get() method
public SecurityAgency getSecurityAgencyById(int id) {
Session session = this.sessionFactory.getCurrentSession();
session.enableFilter("byEnabled");
SecurityAgency s = (SecurityAgency)session.get(SecurityAgency.class, new Integer(id));
return s;
}
Filter starts working as soon as I replace the session.get method with session.createQuery method and send a HQL query. I am unable to find any reason for this behaviour in the hibernate documentation.
FIlter declaration in securtiy agency class
#Entity
#Table(name="security_agency")
public class SecurityAgency implements java.io.Serializable {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name="name")
private String name;
#Column(name="code")
private String code;
#Column(name="website")
private String website;
#Column(name="tan")
private String tan;
#Column(name="email")
private String email;
#Column(name="pan")
private String pan;
#Column(name="created_at")
private Date createdAt;
#Column(name="created_by")
private long createdBy;
#Column(name="modified_at")
private Date modifiedAt;
#Column(name="modified_by")
private long modifiedBy;
#OneToMany(mappedBy="securityAgency",fetch = FetchType.EAGER)
#JsonIgnoreProperties("securityAgency")
#Filter(name = "byEnabled", condition = "is_enabled= 1")
private Set<ContactPerson> contactPersons = new HashSet<ContactPerson>(0);
public SecurityAgency() {
}
Contact person class
#Entity
#Table(name = "contact_person")
#FilterDefs({
#FilterDef(name="byEnabled"),
#FilterDef(name="bySecurityAgency",parameters = #ParamDef(name="agency_id", type="int"))
})
#Filters({
#Filter(name="byEnabled", condition = "is_enabled = 1"),
#Filter(name="bySecurityAgency", condition = "agency_id= :agency_id ")
})
public class ContactPerson implements java.io.Serializable {
Filter doesn't work if you are fetching using id value.Use Query interface instead. See this thread
if you want to use table column values you need to use filter join table ( #FilterJoinTable ), #Filter is applied to target entity rather than table
try,
#FilterJoinTable(name = "byEnabled", condition = "is_enabled= :enabled")
private Set<ContactPerson> contactPersons = new HashSet<ContactPerson>(0);
get
session.enableFilter("byEnabled").setParameter("enabled", Integer.valueOf(1));

How to save or update OneToMany Column with value Null in JPA (Using Play Framework)

I'm currently developing a system using PLAY framework and JPA. My problem is that I can't save an EMPLOYEE if Department_id (which is connected to another Entity class) is Null or has no value.
Here is my Employees Entity Class
#Entity
public class Employees{
#Id
public int employee_id;
public String first_name;
public String last_name;
public String email;
public String phone_number;
public java.sql.Date hire_date;
public String salary;
public String commission_pct;
#ManyToOne
#JoinColumn(name="department_id",nullable = true)
private Departments department_id;
#ManyToOne
#JoinColumn(name="job_id")
private Jobs job_id;
#ManyToOne
#JoinColumn(name="manager_id",nullable = true)
private Employees manager_id;
#OneToMany(mappedBy = "manager_id")
Set<Employees> emps = new HashSet<Employees>();
}
Here is my Departments Entity Class.
#Entity
public class Departments {
#Id
private String department_id;
private String department_name;
private int manager_id;
#OneToMany(mappedBy="department_id")
private Set<Employees> emps = new HashSet<Employees>();
}
Here is the error
Caused by: org.hibernate.TransientObjectException: object references an unsaved
transient instance - save the transient instance before flushing: modelsDomain.E
mployees.department_id -> modelsDomain.Departments
at org.hibernate.engine.CascadingAction$9.noCascade(CascadingAction.java
:387) ~[hibernate-core-3.6.9.Final.jar:3.6.9.Final]
at org.hibernate.engine.Cascade.cascade(Cascade.java:172) ~[hibernate-co
re-3.6.9.Final.jar:3.6.9.Final]
at org.hibernate.event.def.AbstractFlushingEventListener.cascadeOnFlush(
AbstractFlushingEventListener.java:154) ~[hibernate-core-3.6.9.Final.jar:3.6.9.F
inal]
at org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFl
ushes(AbstractFlushingEventListener.java:145) ~[hibernate-core-3.6.9.Final.jar:3
.6.9.Final]
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverything
ToExecutions(AbstractFlushingEventListener.java:88) ~[hibernate-core-3.6.9.Final
.jar:3.6.9.Final]
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlus
hEventListener.java:50) ~[hibernate-core-3.6.9.Final.jar:3.6.9.Final]

JPA Bi-directional Remove

In OpenJPA, I try to remove an entity with a bi-directional mapping to another entity. I did "find" and then "remove" but I have got an exception of "Encountered deleted object". Can someone provide me a working example?
#Entity
#Table(name="Order")
public class Order implements Serializable {
#EmbeddedId
private OrderPK pk;
...
#OneToOne(cascade=CascadeType.ALL, mappedBy="order")
private Invoice invoice;
}
#Entity
#Table(name="Invoice")
public class Invoice implements Serializable {
#EmbeddedId
private InvoicePK pk;
...
#OneToOne
#PrimaryKeyJoinColumn
private Order order;
}
#Embeddable
public class OrderPK implements Serializable {
private String id;
private Date date;
...
}
#Embeddable
public class InvoicePK implements Serializable {
private String id;
private Date date;
...
}
First, I add them in a single transaction and commit:
Order order = new Order(...);
order.set...
Invoice invoice = new Invoice(...);
invoice.set...
order.setInvoice(invoice);
invoice.setOrder(order);
em.persist(order);
Then when I try to remove the order, I expect the invoice will be gone too:
Order order = em.find(Order.class, orderPK); em.remove(order);
but I have an exception instead saying:
Encountered deleted object "org.apache.openjpa.enhance.Order$pcsubclass-
Order-OrderPK#92882281" in persistent field "Invoice.order" of managed
object "Invoice$pcsubclass-InvoicePK#92882281" during flush.

Categories