I am using Java EE 6. Just want to throw it out there first
Here is the relationship. Acustomer
can have multiple facility
Here is Customer Class
@Entity
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="CUSTOMER_FK", nullable=false)
private List<Facility> facilities;
public Customer(){
facilities = new ArrayList<Facility>();
}
public Customer(Long id, String name, List<Facility> facilities) {
this.id = id;
this.name = name;
this.facilities = facilities;
}
//set and get method
...
public void addFacility(Facility facility){
this.facilities.add(facility);
}
}
Here is Facility Class
@Entity
public class Facility {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
public Facility(){}
public Facility(Long id, String name, Address address, List<Project> project) {
this.id = id;
this.name = name;
}
//Set and get method
...
}
Now in main if I just have this, then it work fine. I can see this get insert into my database
Customer customer = new Customer();
customer.setName("Wake Forest University");
EntityManagerFactory emf = Persistence.createEntityManagerFactory("EntityLibraryPU");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
em.persist(customer);
tx.commit();
However, as soon as I try to add facility and force FK constrain. Things start to break.
Customer customer = new Customer();
customer.setName("Wake Forest University");
Facility facility = new Facility();
facility.setName("Xia");
customer.addFacility(facility);
EntityManagerFactory emf = Persistence.createEntityManagerFactory("EntityLibraryPU");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
em.persist(customer);
tx.commit();
Here is the error. First I get double of the same "Wake Forest University" customer insert into CUSTOMER table (not name
attribute is not set to unique, it is that it insert two entries at one time into the database). However, nothing get insert into my FACILITY table. Any idea why? One of the error code is Field 'customer_fk' doesn't have a default value
. May开发者_运维技巧be that can hint you guys a bit. I have no idea. When I look into the error log :Call: INSERT INTO FACILITY (ID, NAME, STREET2, STREET1, ZIPCODE, STATE, CITY, COUNTRY) VALUES (?, ?, ?, ?, ?, ?, ?, ?)bind => [2, Xia, null, null, null, null, null, null]
, my FACILITY
table, have a field CUSTOMER_FK
, which is created when I try to force one-to-many relationship between CUSTOMER
and FACILITY
, but the query never insert anything into that field
First I get double of the same "Wake Forest University" customer insert into CUSTOMER table
Well, you didn't define any uniqueness constraint on the name
of the Customer
entity so nothing prevents this (both records have different PK though). If you want to enforce uniqueness of the name
, set a unique constraint:
@Column(unique=true)
String name;
One of the error code is Field 'customer_fk' doesn't have a default value.
I think that the commented line is "guilty":
tx.begin();
em.persist(customer);
//em.persist(facility); //DON'T DO THIS
tx.commit();
First, the facility doesn't know anything about its customer (this is a uni-directional association, from Customer
to Facitlity
), so JPA can't set the FK, hence the error message.
Second, because you're cascading all operations from the Customer
to Facility
(with the cascade=CascadeType.ALL
in the @OneToMany
annotation), you don't need to persist
the facility
instance.
So, just don't call persist on the facility
instance, let JPA cascade things from the customer
.
You get the duplicate-named customer because there is no unique constraint on the name
column, so running the second test adds the same named customer once again. Add unique=true
to customer name and the column will be enforced to be unique. You will then hit a problem that you cannot create a second Customer with the same name.
The Facility does not need to be explicitly saved, since that is also saved in cascade when you save the Customer.
In fact, you also cannot persist the facility directly since it doesn't have it's own table. By using a @JoinColumn
, you remove the use of a join table between Customer and Facility and put the customer foreign key in the Facuility table. If you remove the @JoinColumn, then you will see an addtional join table like CUSTOMER_FACILITY, which stores the mapping of customers to facilities. Then, you can persist a facility independently.
精彩评论