У меня есть 2 лица Customer & Adress следующим образом:
Customer.java
package com.hibernaterecipes.chapter5;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name="CUSTOMER")
public class Customer {
@Column (name="ID")
@Id
@GeneratedValue (strategy=GenerationType.AUTO)
private Long id;
@Column (name="COUNTRY_CODE")
private String countryCode;
@Column (name="ID_CARD_NO")
private String idCardNo;
@Column (name="FIRST_NAME")
private String firstName;
@Column (name="LAST_NAME")
private String lastName;
@Column (name="EMAIL")
private String email;
@OneToOne (cascade=CascadeType.ALL)
@JoinTable (name="CustomerAddress",
joinColumns=@JoinColumn(name="ID"),
inverseJoinColumns=@JoinColumn(name="ADDRESS_ID"))
private Address address;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCountryCode() {
return countryCode;
}
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
public String getIdCardNo() {
return idCardNo;
}
public void setIdCardNo(String idCardNo) {
this.idCardNo = idCardNo;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
Адрес.java:
package com.hibernaterecipes.chapter5;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name="ADDRESS")
public class Address {
@Id
@Column (name="ADDRESS_ID")
@GeneratedValue (strategy=GenerationType.AUTO)
private Long id;
@Column(name="CITY")
private String city;
@Column(name="STREET")
private String street;
@Column(name="DOOR_PLATE")
private String doorplate;
@OneToOne (mappedBy="address")
private Customer customer;
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getDoorplate() {
return doorplate;
}
public void setDoorplate(String doorplate) {
this.doorplate = doorplate;
}
}
Когда я пытаюсь сохранить клиента, я получаю следующую трассировку стека:
Exception in thread "main" org.hibernate.PropertyValueException: not-null property references a null or transient value: com.hibernaterecipes.chapter5.Address.customer
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:284)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:180)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:108)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:98)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499)
at org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.java:218)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:268)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:216)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:412)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:261)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:180)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:108)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:535)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:523)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:519)
at com.hibernaterecipes.chapter5.Launch5_6A.main(Launch5_6A.java:29)
Я пытался добавить @NotNull в обе стороны.optional = false в @OneToOne & unique = true, nullable = false в @JoinColumn, но ничего не помогло.
Pl. помощь.
Согласно совету я изменил свой класс адресов
package com.hibernaterecipes.chapter5;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name="ADDRESS")
public class Address {
@Id
@Column (name="ADDRESS_ID")
@GeneratedValue (strategy=GenerationType.AUTO)
private Long id;
@Column(name="CITY")
private String city;
@Column(name="STREET")
private String street;
@Column(name="DOOR_PLATE")
private String doorplate;
@OneToOne(mappedBy="address")
private Customer customer;
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
if (null != customer) {
customer.setAddress(this);
this.customer = customer;
}
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getDoorplate() {
return doorplate;
}
public void setDoorplate(String doorplate) {
this.doorplate = doorplate;
}
}
Класс клиента остается неизменным.
Для тестирования класса помощника по коду
JpaUtil.java
package persistence;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
public class JpaUtil {
private static SessionFactory sessionFactory;
static {
try {
sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
// Alternatively, we could look up in JNDI here
return sessionFactory;
}
public static void shutdown() {
// Close caches and connection pools
getSessionFactory().close();
}
}
Основной класс для тестирования Launch5_6A.java
package com.hibernaterecipes.chapter5;
import org.hibernate.Session;
import org.hibernate.Transaction;
import persistence.JpaUtil;
public class Launch5_6A {
/**
* @param args
*/
public static void main(String[] args) {
Customer customer = new Customer();
customer.setCountryCode("India");
customer.setEmail("subhendu_mahanta@yahoo.com");
customer.setFirstName("Subhendu");
customer.setLastName("Mahanta");
customer.setIdCardNo("43223");
Address address = new Address();
address.setCity("Pune");
address.setDoorplate("E1/33");
address.setStreet("Paud Road");
address.setCustomer(customer);
customer.setAddress(address);
Session session = JpaUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
session.save(customer);
tx.commit();
session.close();
}
}
Результат остается прежним.
07:54:37,265 INFO Version:15 - Hibernate Annotations 3.2.0.CR3
07:54:37,296 INFO Environment:500 - Hibernate 3.2.0.cr5
...
Exception in thread "main" org.hibernate.PropertyValueException: not-null property references a null or transient value: com.hibernaterecipes.chapter5.Address.customer
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:284)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:180)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:108)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:98)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499)
at org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.java:218)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:268)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:216)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:412)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:261)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:180)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:108)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:535)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:523)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:519)
at com.hibernaterecipes.chapter5.Launch5_6A.main(Launch5_6A.java:29)
07:54:39,734 INFO SchemaUpdate:160 - schema update complete
07:54:39,734 DEBUG DriverManagerConnectionProvider:129 - returning connection to pool, pool size: 1
07:54:39,734 DEBUG SessionFactoryImpl:390 - Checking 0 named HQL queries
07:54:39,734 DEBUG SessionFactoryImpl:410 - Checking 0 named SQL queries
07:54:39,796 DEBUG SessionImpl:220 - opened session at timestamp: 12963542797
07:54:39,796 DEBUG JDBCTransaction:54 - begin
07:54:39,796 DEBUG ConnectionManager:415 - opening JDBC connection
07:54:39,796 DEBUG DriverManagerConnectionProvider:93 - total checked-out connections: 0
07:54:39,796 DEBUG DriverManagerConnectionProvider:99 - using pooled JDBC connection, pool size: 0
07:54:39,796 DEBUG JDBCTransaction:59 - current autocommit status: false
07:54:39,796 DEBUG JDBCContext:210 - after transaction begin
07:54:39,796 DEBUG DefaultSaveOrUpdateEventListener:161 - saving transient instance
07:54:39,796 DEBUG AbstractSaveEventListener:152 - saving [com.hibernaterecipes.chapter5.Customer#<null>]
07:54:39,796 DEBUG AbstractSaveEventListener:240 - executing insertions
07:54:39,812 DEBUG Cascade:115 - processing cascade ACTION_SAVE_UPDATE for: com.hibernaterecipes.chapter5.Customer
07:54:39,812 DEBUG CascadingAction:216 - cascading to saveOrUpdate: com.hibernaterecipes.chapter5.Address
07:54:39,812 DEBUG AbstractSaveEventListener:489 - transient instance of: com.hibernaterecipes.chapter5.Address
07:54:39,812 DEBUG DefaultSaveOrUpdateEventListener:161 - saving transient instance
07:54:39,812 DEBUG AbstractSaveEventListener:152 - saving [com.hibernaterecipes.chapter5.Address#<null>]
07:54:39,812 DEBUG AbstractSaveEventListener:240 - executing insertions