Spring数据JPA save会导致子实体出错

时间:2014-11-19 15:55:10

标签: database spring hibernate jpa

我是Spring Data JPA和CRUD存储库的新手。如果我保存每个单独的实体,我有可以保存到数据库的代码,但我认为我应该能够保存父实体并自动保存或更新包含的子实体。我做错了吗?

执行保存的代码:

private static CustomerRepository customerRepository;

@Transactional
public ResultCreateCustomer addCustomer(NameTable nameIn, Address addressIn)
        throws Exception {
    AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
    customerRepository = context.getBean(CustomerRepository.class);
    ResultCreateCustomer result = new ResultCreateCustomer(0, 0, 0, DATABASE_OR_SYSTEM_ERROR);
    try {
        NameTable theName = new NameTable();
        theName.setFirstName(nameIn.getFirstName());
        theName.setLastName(nameIn.getLastName());

        Address theAddress = new Address();
        theAddress.setStreetNo(addressIn.getStreetNo());
        theAddress.setStreetName(addressIn.getStreetName());
        theAddress.setCityStateZip(addressIn.getCityStateZip());

        Customer theCustomer = new Customer();
        theCustomer.setNameTable(theName);
        theCustomer.setAddress(theAddress);
        customerRepository.save(theCustomer);
    } catch (Exception e) {
        this.log.error("got exception: " + e.getClass() + ": " + e.getMessage());
    } 

    context.close();
    return result;
}

客户实体的代码:

@Entity
@org.hibernate.annotations.Proxy(lazy=false)
@Table(name="Customer")
public class Customer implements Serializable {
    public Customer() {
    }
    @Column(name="ID", nullable=false, unique=true) 
    @Id 
    @GeneratedValue(generator="COM_COMPORIUM_CUSTOMER_DOMAIN_CUSTOMER_ID_GENERATOR")    
    @org.hibernate.annotations.GenericGenerator(name="COM_COMPORIUM_CUSTOMER_DOMAIN_CUSTOMER_ID_GENERATOR", strategy="native")  
    private int ID;

    @ManyToOne(targetEntity=com.comporium.customer.addresses.Address.class, fetch=FetchType.LAZY)   
    @org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.LOCK})    
    @JoinColumns({ @JoinColumn(name="AddressID", referencedColumnName="ID") })  
    private com.comporium.customer.addresses.Address address;

    @OneToOne(targetEntity=com.comporium.customer.contactrolodex.NameTable.class, fetch=FetchType.LAZY) 
    @org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.LOCK}) 
    @JoinColumns({ @JoinColumn(name="NameTableID", nullable=false) })   
    private com.comporium.customer.contactrolodex.NameTable nameTable;

    @Column(name="IndustryCode", nullable=false)    
    private int industryCode;

    @Column(name="DemographicCode", nullable=false) 
    private int demographicCode;

    @Column(name="Ranking", nullable=false) 
    private int ranking;

    public void setNameTable(com.comporium.customer.contactrolodex.NameTable value) {
        this.nameTable = value;
    }
    public com.comporium.customer.contactrolodex.NameTable getNameTable() {
        return nameTable;
    }
    // Other setters and getters follow
}

第一个子类的代码:

@Entity
@org.hibernate.annotations.Proxy(lazy=false)
@Table(name="NameTable")
public class NameTable implements Serializable {
    public NameTable() {
    }

    @Column(name="ID", nullable=false, unique=true) 
    @Id 
    @GeneratedValue(generator="COM_COMPORIUM_CUSTOMER_CONTACTROLODEX_NAMETABLE_ID_GENERATOR")   
    @org.hibernate.annotations.GenericGenerator(name="COM_COMPORIUM_CUSTOMER_CONTACTROLODEX_NAMETABLE_ID_GENERATOR", strategy="native") 
    private int ID;

    @Column(name="FirstName", nullable=true, length=30) 
    private String firstName;

    @Column(name="LastName", nullable=true, length=40)  
    private String lastName;

    @OneToOne(mappedBy="nameTable", targetEntity=com.comporium.customer.domain.Customer.class, fetch=FetchType.LAZY)    
    @org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.LOCK}) 
    private com.comporium.customer.domain.Customer customer;
}

存储库接口CustomerRepository:

package com.comporium.customer.repositories;
import org.springframework.data.repository.CrudRepository;
import com.comporium.customer.domain.Customer;

public interface CustomerRepository extends CrudRepository<Customer, Integer> {
}

当我运行可执行文件(通过SOAP调用)时,我得到一个例外:

2014-11-19 09:57:59,253 ERROR VPcodeDao:306 - got exception: class org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation: com.comporium.customer.domain.Customer.nameTable -> com.comporium.customer.contactrolodex.NameTable; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation: com.comporium.customer.domain.Customer.nameTable -> com.comporium.customer.contactrolodex.NameTable

还有一种方法可以让save(theCustomer)保存包含的子实体吗?

1 个答案:

答案 0 :(得分:0)

不确定是否可以找到解决方案。但是解决方案是定义级联

@OneToOne(cascade = {CascadeType.ALL}, mappedBy="nameTable", targetEntity=com.comporium.customer.domain.Customer.class, fetch=FetchType.LAZY)