saving of entity in the database causes unexpected behaviors - java

When I try persist the entity below in the database, in a application which uses spring and hibernate, in the way it's presented, I get the error object references an unsaved transient instance - save the transient instance before flushing; but if I add the value cascade = CascadeType.ALL to the annotation #OneToOne (or add the annotation #Cascade), for each attribute I don't fill it's inserted an empty record in the database.
#Entity
#Table(name="cliente")
public class Cliente {
#Id
#Column(name = "id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name="usuario")
#Order(value=1)
private Usuario usuario;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name="pessoa_fisica")
#Order(value=2)
private PessoaFisica pessoaFisica;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name="pessoa_juridica")
#Order(value=3)
private PessoaJuridica pessoaJuridica;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name="endereco_entrega")
#Order(value=4)
private Endereco endereco_entrega;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name="endereco_cobranca")
#Order(value=5)
private Endereco endereco_cobranca;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name="pedidos_do_cliente", joinColumns={#JoinColumn(name="fk_cliente")}, inverseJoinColumns={#JoinColumn(name="fk_pedido")})
#Order(value=6)
private List<Pedido> pedido;
}
Anyone can tell me how to fix this problem?
ps.: below the related method which handle this process:
controller
#RequestMapping(value="cadastra", method=RequestMethod.POST)
#ResponseBody
public String cadastra(#ModelAttribute("object") E object, BindingResult result, #RequestParam(value="file", required=false) MultipartFile file, #RequestParam(value="icone", required=false) MultipartFile icone) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException {
serv.cadastra(object);
serv.upload_picture(object, file, "picture");
serv.upload_picture(object, icone, "icone");
return "";
}
service
#Transactional
public void cadastra(E e) {
dao.persist(e);
}
dao class
#Transactional
public void persist(E transientInstance) {
sessionFactory.getCurrentSession().persist(transientInstance);
}
UPDATE
CREATE TABLE cliente
(
id serial NOT NULL,
endereco_cobranca integer,
endereco_entrega integer,
pessoa_fisica integer,
pessoa_juridica integer,
usuario integer,
CONSTRAINT cliente_pkey PRIMARY KEY (id),
CONSTRAINT fk_4taj5h8hxci6slrw0n3d336i7 FOREIGN KEY (endereco_entrega)
REFERENCES endereco (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT fk_7a5l0l5enj00apelvmcdatkmm FOREIGN KEY (pessoa_juridica)
REFERENCES pessoa_juridica (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT fk_iiibo76b56caciax4yl0jo0m6 FOREIGN KEY (pessoa_fisica)
REFERENCES pessoa_fisica (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT fk_lwavy2v0wb0vmxisg7hbe3mbu FOREIGN KEY (usuario)
REFERENCES usuario (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT fk_r2pyppeltv7xoe5quenf2l1gd FOREIGN KEY (endereco_cobranca)
REFERENCES endereco (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (
OIDS=FALSE
);
ALTER TABLE cliente
OWNER TO klebermo;

In your view layer, are you creating new objects for the these linked columns? or in the controller that serves the form, are you adding 'new' objects to the model? It seems as though you have created empty java objects for these one-to-one columns which is why you cant save the parent without saving the children and why with cascade option it creates empty records.

Related

HIbernate Can't delete Entity with foreign key. Foreign key gets set to null

This question has been asked in many forms here but none of the solutions seem to work for me. I'm trying to delete the parent entity and I want all of the child entities to also be deleted.
My entities:
#Entity
#Table(name = "item", catalog = "myshchema")
public class Item implements java.io.Serializable {
#JoinColumn(name = "item_id", insertable = false, updatable = false, nullable = false)
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
private Set<ItemCategory> categories;
/* Getters and Setters and other fields*/
}
Table for Item:
CREATE TABLE `item` (
`item_id` int(11) NOT NULL AUTO_INCREMENT,
`store_id` int(11) NOT NULL,
PRIMARY KEY (`item_id`),
UNIQUE KEY `item_id_UNIQUE` (`item_id`),
KEY `FK_ITEM_STORE_ID_idx` (`store_id`),
CONSTRAINT `FK_ITEM_STORE_ID` FOREIGN KEY (`store_id`) REFERENCES `store` (`store_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=84 DEFAULT CHARSET=utf8;
And my other entity
#Entity
#Table(name = "item_category", catalog = "myschema")
#IdClass(ItemCategoryIndex.class)
public class ItemCategory implements java.io.Serializable {
#Id
#Column(name = "category_id", unique = true, nullable = false, insertable = false, updatable = false)
private Integer categoryId;
#Id
private Store store;
#Id
private Item item;
#Id
private String categoryName;
/* Getters and Setters */
}
Table for ItemCategory:
CREATE TABLE `item_category` (
`category_id` int(11) NOT NULL AUTO_INCREMENT,
`store_id` int(11) NOT NULL,
`item_id` int(11) NOT NULL,
`category_name` varchar(45) NOT NULL,
PRIMARY KEY (`category_id`),
UNIQUE KEY `category_id_UNIQUE` (`category_id`),
UNIQUE KEY `IDX_UNIQUE_STORE_CATEGORY` (`store_id`,`item_id`,`category_name`) USING BTREE,
KEY `FK_CATEGORY_STORE_ID_idx` (`store_id`),
KEY `FK_ITEM_CATEGORY_ID_idx` (`item_id`),
CONSTRAINT `FK_CATEGORY_STORE_ID` FOREIGN KEY (`store_id`) REFERENCES `store` (`store_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `FK_ITEM_CATEGORY_ID` FOREIGN KEY (`item_id`) REFERENCES `item` (`item_id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=162 DEFAULT CHARSET=utf8;
I try to delete the item like this:
Item item = entityManager.find(Item.class, idList.get(i));
entityManager.remove(item);
My logs show that Hibernate is trying to set the primary key for ItemCategory to null:
Hibernate: update myschema.item_category set item_id=null where item_id=?
ERROR o.h.e.jdbc.spi.SqlExceptionHelper.logExceptions 146 - Column 'item_id' cannot be null
I even tried looping through the child records and deleting them manually, but Hibernate still issues this update to null query. What am I doing wrong?
I have to break your problem down to two parts
First - let's talk about your database schema design.
According to your schema, item and item_category has a one-to-many relationship meaning an item can have/be-assigned-to different categories but different items cannot have/be-assigned-to the same category.
That is totally fine if it is indeed your business requirement, I mention it because it does not make sense to me and this circumstance rarely happens.
If what you want is that a category can have multiple items and vice versa, itemand item_category must be a many-to-many relationship. There should be a join table additionally.
Second - let's say the schema don't change
ItemCategory is the owner of the relationship because it has a foreign key item_id refering to item table. So the ItemCategoy should look roughly like this:
#Entity
#Table(name = "item_category")
public class ItemCategory {
#Id
private Integer categoryId;
private Store store;
#ManyToOne
#JoinColumn(name="item_id", /*cascade = ...*/)
private Item item;
private String categoryName;
/* Getters and Setters */
}
Your Item entity will be roughly like this:
#Entity
#Table(name = "item", catalog = "myshchema")
public class Item implements java.io.Serializable {
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true, mappedBy="item")
private Set<ItemCategory> categories; //`mappedBy`used here because this entity is not the owner of the relationship according to what mentioned above
/* Getters and Setters and other fields*/
}
To remove all the child entities(ItemCategory) from Item , simply
em.remove(item);
The orphanRemoval is true, deleting the parent, the children will be deleted as well.
In Hibernate, you need to decide who is owning the relationship. If you have the parent side (ItemCategory) owning the relationship, you will find insertion/deletion of Item+ ItemCategory will involve update of item_id in ItemCategory table (which is what I observed from your exception). In most case it is not preferable. We usually let the children own the relationship. This is done by using mappedBy
(pseudo-code)
class Item {
//...
#OneToMany(mappedBy = "item", cascade=ALL, orphanRemoval=true)
private Set<ItemCategory> categories;
}
class ItemCategory {
//...
#ManyToOne
#JoinColumn(name="item_id")
Item item;
}
The trick here is mappedBy

Hibernate (Spring JPA) child entities removal

I'm learning Hibernate (Spring) and facing strange issue with removing child entities from the parent one.
Here is what I have:
Parent entity:
#Entity
public class Company {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "company_id", referencedColumnName = "id")
List<CompanyObject> companyObjects;
}
Child entity:
#Entity
public class CompanyObject {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
#Enumerated(EnumType.STRING)
ObjectType type;
#ManyToOne
#JoinColumn(name = "company_id")
Company company;
}
Here is my table definitions:
CREATE TABLE `company` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8
CREATE TABLE `company_object` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`company_id` bigint(20) NOT NULL,
`type` varchar(50) NOT NULL,
PRIMARY KEY (`id`),
KEY `FK__company` (`company_id`),
CONSTRAINT `FK__company` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
And, also, I have the following update method:
// some code here
public void update(CompanyDto dto) {
Company company = repository.getCompanyById(companyId);
repository.save(dto.merge(company));
}
// some code here
public class CompanyDto {
private List<CompanyObjectDto> companyObjects = new ArrayList<>();
public Company merge(Company company) {
company.getCompanyObjects().clear();
for (CompanyObjectDto dto : companyObjects) {
company.getCompanyObjects().add(dto.to(company));
}
return company;
}
}
public class CompanyObjectDto {
ObjectType type;
public CompanyObject to(Company company) {
CompanyObject object = new CompanyObject();
object.setType(this.getType());
object.setCompany(company);
return object;
}
}
And as soon as I launch update method, I get the following error: java.sql.SQLWarning: Column 'company_id' cannot be null. I investigated this a little bit and found out that if I comment out company.getCompanyObjects().clear(); string it works ok, so it seems there is some problem with cascading delete action to company objects.
Could, please, somebody point me to my mistakes? Thanks.
You have mapped your entities Company and CompanyObject bidirectionally, i.e. both entities have a relation to the other entity.
In this case, there should only be one #Joincolumn and one entity must be selected as the owning entity, with the other entity marking the relation with a 'mappedby' (see http://docs.oracle.com/javaee/6/api/javax/persistence/ManyToOne.html).
You are getting error because you are removing object's from List and then use the same List as a reference to your Company object. See below code :
private List<CompanyObjectDto> companyObjects = new ArrayList<>(); //Stmt 1
Above code is used to define list which will be reference in your below code :
company.getCompanyObjects().clear(); //It will clear out all objects
for (CompanyObjectDto dto : companyObjects) { //Iterating over empty list defined in stmt 1.
company.getCompanyObjects().add(dto.to(company));
}
So your foreign key will always be null which is not permitted and throws exception.
And your code works when you comment out List#clear line because in that scenario, list already have some referenced objects which didn't modify.

How to delete entity which associated with java map list

I have an entity which has map list with sub enitities. When I want to delete this entity , I've got
Cannot delete or update a parent row: a foreign key constraint fails (kobalt.category_categoryitem,
error and I use hibernate. Is there anyone who can solve this problem ?
#Entity
public class Product implements BaseEntity {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private int id;
private int kobilId;
private String code;
#Column(unique = true)
private long barcode;
private String productName;
#Column
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#Fetch(value = FetchMode.SUBSELECT)
#Cascade(org.hibernate.annotations.CascadeType.DELETE)
private Map<Category, CategoryItem> itemList;
Looks like relationship structure is not correct in your case. When you are trying to delete foreign key corresponding value it can't delete primary key corresponding value. In cascade rule relationship should be like as when you delete primary key corresponding attribute then it should delete all foreign key corresponding attributes. But can't be vice-versa. That is your case i think so try to correct your relationships. For example consider "employee - address" relationship where employee has array of address. So relationship should be like as when employee is deleted, all the corresponding address should vanish. But on the other hand if relationship is not correct and you try to delete an address then it can't be possible to delete employee, as a result you'll get such exception as in your case.

Error when persisting entity with foreign key field

I am try persist in database this entity:
#Entity
#Table(name="pessoa_juridica")
public class PessoaJuridica {
#Id
#Column(name = "id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#Column(name="cnpj")
#Order(value=1)
private String cnpj;
#Column(name="razao_social")
#Order(value=2)
private String razaoSocial;
#OneToOne( fetch = FetchType.EAGER, cascade = {CascadeType.ALL} )
#Order(value=3)
#JoinColumn(name="contato")
private Contato contato;
}
but when I open the view with the form, I get this error:
org.springframework.beans.NullValueInNestedPathException: Invalid property 'pessoaJuridica.contato' of bean class [com.spring.loja.model.cliente.persistence.model.Cliente]: Could not instantiate property type [java.lang.Integer] to auto-grow nested property path:
java.lang.InstantiationException:
java.lang.Integerorg.springframework.beans.BeanWrapperImpl.newValue(BeanWrapperImpl.java:651)
org.springframework.beans.BeanWrapperImpl.createDefaultPropertyValue(BeanWrapperImpl.java:620)
org.springframework.beans.BeanWrapperImpl.setDefaultValue(BeanWrapperImpl.java:609)
org.springframework.beans.BeanWrapperImpl.getNestedBeanWrapper(BeanWrapperImpl.java:574)
org.springframework.beans.BeanWrapperImpl.getBeanWrapperForPropertyPath(BeanWrapperImpl.java:548)
org.springframework.beans.BeanWrapperImpl.getBeanWrapperForPropertyPath(BeanWrapperImpl.java:549)
org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:714)
org.springframework.validation.AbstractPropertyBindingResult.getActualFieldValue(AbstractPropertyBindingResult.java:99)
org.springframework.validation.AbstractBindingResult.getFieldValue(AbstractBindingResult.java:229)
org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:120)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:168)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:188)org.springframework.web.servlet.tags.form.LabelTag.autogenerateFor(LabelTag.java:130)org.springframework.web.servlet.tags.form.LabelTag.resolveFor(LabelTag.java:120)org.springframework.web.servlet.tags.form.LabelTag.writeTagContent(LabelTag.java:90)org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal(AbstractFormTag.java:84)org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:80)org.apache.jsp.WEB_002dINF.jsp.common.fields_jsp._jspx_meth_form_005flabel_005f13(fields_jsp.java:2969)org.apache.jsp.WEB_002dINF.jsp.common.fields_jsp._jspx_meth_c_005fwhen_005f17(fields_jsp.java:2836)org.apache.jsp.WEB_002dINF.jsp.common.fields_jsp._jspx_meth_c_005fchoose_005f3(fields_jsp.java:2583)org.apache.jsp.WEB_002dINF.jsp.common.fields_jsp._jspx_meth_c_005fforEach_005f4(fields_jsp.java:2539)org.apache.jsp.WEB_002dINF.jsp.common.fields_jsp._jspx_meth_c_005fwhen_005f14(fields_jsp.java:2444)org.apache.jsp.WEB_002dINF.jsp.common.fields_jsp._jspx_meth_c_005fchoose_005f0(fields_jsp.java:242)org.apache.jsp.WEB_002dINF.jsp.common.fields_jsp._jspx_meth_c_005fforEach_005f0(fields_jsp.java:150)org.apache.jsp.WEB_002dINF.jsp.common.fields_jsp._jspService(fields_jsp.java:115)org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)javax.servlet.http.HttpServlet.service(HttpServlet.java:728)org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)javax.servlet.http.HttpServlet.service(HttpServlet.java:728)org.apache.jasper.runtime.JspRuntimeLibrary.include(JspRuntimeLibrary.java:954)org.apache.jsp.WEB_002dINF.jsp.private_.cadastrar_jsp._jspx_meth_form_005fform_005f0(cadastrar_jsp.java:166)org.apache.jsp.WEB_002dINF.jsp.private_.cadastrar_jsp._jspService(cadastrar_jsp.java:88)org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)javax.servlet.http.HttpServlet.service(HttpServlet.java:728)org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)javax.servlet.http.HttpServlet.service(HttpServlet.java:728)org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:209)org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:267)org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1217)org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1005)org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:952)org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)javax.servlet.http.HttpServlet.service(HttpServlet.java:621)org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)javax.servlet.http.HttpServlet.service(HttpServlet.java:728)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
the setter/getter methods for Contato are:
public Integer getContato() {
return contato.getId();
}
public void setContato(Integer id) {
this.contato = new Contato(id);
}
the class Contatois this:
#Entity
#Table(name="contato")
public class Contato {
#Id
#Column(name = "id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#Column(name="nome", unique=true)
#Order(value=1)
private String nome;
#Column(name="email")
#Order(value=2)
private String email;
#Column(name="telefone")
#Order(value=3)
private String telefone;
public Contato() {
this.id = null;
this.nome = null;
this.email = null;
this.telefone = null;
}
public Contato(Integer id) {
this.id = id;
}
}
If I try this for the setter/getter method:
public Contato getContato() {
return contato;
}
public void setContato(Contato contato) {
this.contato = contato;
}
the view is opened, but when I try submit the form, I get the error:
org.hibernate.PersistentObjectException: detached entity passed to persist: com.spring.loja.model.contato.persistence.model.Contatoorg.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:139)org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:801)org.hibernate.internal.SessionImpl.persist(SessionImpl.java:794)org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:314)org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:350)org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:293)org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:161)org.hibernate.engine.internal.Cascade.cascade(Cascade.java:118)org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:432)org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:265)org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:194)org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:206)org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:149)org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:801)org.hibernate.internal.SessionImpl.persist(SessionImpl.java:794)org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:314)org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:350)org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:293)org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:161)org.hibernate.engine.internal.Cascade.cascade(Cascade.java:118)org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:432)org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:265)org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:194)org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:206)org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:149)org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:811)org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784)org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789)com.spring.loja.config.generic.persistence.Dao.persist(Dao.java:32)com.spring.loja.config.generic.persistence.Dao$$FastClassBySpringCGLIB$$ddbbe880.invoke(<generated>)org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:711)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)com.spring.loja.model.cliente.persistence.ClienteHome$$EnhancerBySpringCGLIB$$83cbd101.persist(<generated>)com.spring.loja.config.generic.service.service.cadastra(service.java:45)com.spring.loja.config.generic.service.service$$FastClassBySpringCGLIB$$c92a3159.invoke(<generated>)org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:711)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:64)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)com.spring.loja.model.cliente.service.ClienteService$$EnhancerBySpringCGLIB$$71ccd54c.cadastra(<generated>)com.spring.loja.config.generic.controller.controller.cadastra(controller.java:42)com.spring.loja.config.generic.controller.controller$$FastClassBySpringCGLIB$$c8cc444b.invoke(<generated>)org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:640)com.spring.loja.model.cliente.controller.ClienteController$$EnhancerBySpringCGLIB$$ffe13d4e_2.cadastra(<generated>)sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)java.lang.reflect.Method.invoke(Method.java:606)org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749)org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689)org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)javax.servlet.http.HttpServlet.service(HttpServlet.java:647)org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)javax.servlet.http.HttpServlet.service(HttpServlet.java:728)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
anyone knows the right way to persist the entity?
UPDATE
the field contato is mapped on the view as this:
<form:label path="pessoaJuridica.contato.id" class="label label-default">contato</form:label>
<form:select path="pessoaJuridica.contato.id" class="form-control select embed" data-lista="${url}" data-altera="${altera}" data-remove="${remove}"/>
UPDATE 2
In database, this is the how tables are created:
CREATE TABLE pessoa_juridica
(
id serial NOT NULL,
cnpj character varying(255),
razao_social character varying(255),
contato integer,
CONSTRAINT pessoa_juridica_pkey PRIMARY KEY (id),
CONSTRAINT fk_eaa4oxajsuofatiyag213dio9 FOREIGN KEY (contato)
REFERENCES contato (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (
OIDS=FALSE
);
ALTER TABLE pessoa_juridica
OWNER TO klebermo;
CREATE TABLE contato
(
id serial NOT NULL,
email character varying(255),
nome character varying(255),
telefone character varying(255),
CONSTRAINT contato_pkey PRIMARY KEY (id),
CONSTRAINT uk_rrtn7wgfxo0jfwkhby23f72cn UNIQUE (nome)
)
WITH (
OIDS=FALSE
);
ALTER TABLE contato
OWNER TO klebermo;
As I remember, the join column name is not the name of the object you are joining to, but the name of the column on the object you are joining to.
You told JPA to cascade all! and passed detached object to save, that is an issue.
According to Hibernate.
CascadeType.PERSIST: cascades the persist (create) operation to
associated entities persist() is called or if the entity is managed
You said #OneToOne( fetch = FetchType.EAGER, cascade = {CascadeType.ALL} ) means it will apply all Transitive persistence.
So removing cascade = {CascadeType.ALL} will solve the prob.
#OneToOne( fetch = FetchType.EAGER)
#Order(value=3)
#JoinColumn(name="contato")
private Contato contato;

Foreign key update anomaly: foreign keys set to null in Hibernate one-to-many relationship

I am finding that when the parent table in a one-to-many relationship is updated, the foreign keys of dependent data on the child table are being set to null leaving orphaned records on the child table.
I have two Java classes annotated with Hibernate tags. The parent table is:
#Entity
#Table(name = "PERSON")
public class Person implements Serializable {
// Attributes.
#Id
#Column(name="PERSON_ID", unique=true, nullable=false)
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer personId;
#Column(name="NAME", nullable=false, length=50)
private String name;
#Column(name="ADDRESS", nullable=false, length=100)
private String address;
#Column(name="TELEPHONE", nullable=false, length=10)
private String telephone;
#Column(name="EMAIL", nullable=false, length=50)
private String email;
#OneToMany(cascade=CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name="PERSON_ID")
private List<Book> books;
And the child table is:
Entity
#Table(name = "BOOK")
public class Book implements Serializable {
// Attributes.
#Id
#Column(name="BOOK_ID", unique=true, nullable=false)
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer bookId;
#Column(name="AUTHOR", nullable=false, length=50)
private String author;
#Column(name="TITLE", nullable=false, length=50)
private String title;
#Column(name="DESCRIPTION", nullable=false, length=500)
private String description;
#Column(name="ONLOAN", nullable=false, length=5)
private String onLoan;
// #ManyToOne
// private Person person;
But when an update is issued on a Person, any Books records related to the parent are set to null.
The Book table is:
CREATE TABLE BOOK (
BOOK_ID INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
AUTHOR VARCHAR(50) NOT NULL,
TITLE VARCHAR(100) NOT NULL,
DESCRIPTION VARCHAR(500) NOT NULL,
ONLOAN VARCHAR(5) NOT NULL,
PERSON_ID INTEGER,
CONSTRAINT PRIMARY_KEY_BOOK PRIMARY KEY(BOOK_ID),
CONSTRAINT FOREIGN_KEY_BOOK FOREIGN KEY(PERSON_ID) REFERENCES PERSON(PERSON_ID))
And the update method in the Person controller is:
#RequestMapping(value = "/profile", method = RequestMethod.POST)
public String postProfile(#ModelAttribute("person") Person person,
BindingResult bindingResult,
Model model) {
logger.info(PersonController.class.getName() + ".postProfile() method called.");
personValidator.validate(person, bindingResult);
if (bindingResult.hasErrors()) {
return "view/profile";
}
else {
personService.update(person);
model.addAttribute("person", person);
return "view/options";
}
}
And the actual DAO level method is:
#Override
public void update(Person person) {
logger.info(PersonDAOImpl.class.getName() + ".update() method called.");
Session session = sessionFactory.openSession();
Transaction transaction = session.getTransaction();
try {
transaction.begin();
session.update(person);
transaction.commit();
}
catch(RuntimeException e) {
Utils.printStackTrace(e);
transaction.rollback();
throw e;
}
finally {
session.close();
}
}
So I'm assuming that update is the cause of the issue but why?
I have tried merge, persist and saveOrUpdate methods as alternatives but to no avail.
Concerning the fact that my Book table has no annotation for #ManyToOne, disabling this tag was the only way in which I could get LAZY fetching to work.
This case also seems very similar to Hibernate one to many:"many" side record's foreign key is updated to null automatically and Hibernate Many to one updating foreign key to null, but if I adopt the changes specified to classes in these questions to my own tables, my application refuses to even compile seemingly because of problems with the use of mappedBy in the Person table.
Any advice is welcome.
Controller method changed to:
// Validates and updates changes made by a Person on profile.jap
#RequestMapping(value = "/profile", method = RequestMethod.POST)
public String postProfile(#ModelAttribute("person") Person person,
BindingResult bindingResult,
Model model) {
logger.info(PersonController.class.getName() + ".postProfile() method called.");
// Validate Person.
personValidator.validate(person, bindingResult);
if (bindingResult.hasErrors()) {
return "view/profile";
}
else {
// Get current Person.
Person currPerson = personService.get(person.getPersonId());
// Set Books to updated Person.
person.setBooks(currPerson.getBooks());
personService.update(person);
model.addAttribute("person", person);
return "view/options";
}
}
And it works.
I assume that the postProfile() method receives a Person instance which only contains the ID, name, address etc. of the person, as posted by a web form, but that its list of books is null or empty.
And you're telling Hibernate to save that person. So you're effectively telling Hibernate that this person, identified by the given ID has a new name, a new address, a new email, ... and a new list of books which happens to be empty, and that this should be saved into the database.
So Hibernate does what you're telling it to do: it saves the new state of the person. And since the new person doesn't have any book, all the books it previously owned become owned by nobody.
You'll have to get the actual, persistent Person entity from the database, and copy the fields that should actually be modified from the new person to the persistent one.
Or you'll have to pre-load the persistent person from the database and make Spring populate this persistent person instead of creating a new instance per scratch. See http://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/htmlsingle/#mvc-ann-modelattrib-methods.
You may also try to remove the #JoinColumn from the #OneToMany, and use mappedBy, instead.
See: Hibernate Many to one updating foreign key to null

Categories