views:

39

answers:

2

I am using Java EE 6. Just want to throw it out there first
Here is the relationship. A customer 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. Maybe 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

+1  A: 

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.

mdma
so what you mean is in this design I dont need to `em.persist(facility)`, correct? It should be cascading through, right? It is not the duplicate-name in my `CUSTOMER` table that I am talking about. It is that it insert two entries of `Wake Forest Univeristy` at one time. So if I have nothing inside `CUSTOMER`, after 1 run, I would have 2 entires in it.
Harry Pham
I took out `em.persist(facility)`, does not solve the problem. Any idea why
Harry Pham
+2  A: 

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.

Pascal Thivent
It is not the duplicate-name in my `CUSTOMER` table that I am talking about. It is that it insert two entries of `Wake Forest Univeristy` at one time. So if I have nothing inside CUSTOMER, after 1 run, I would have 2 entires in it. Now this duplication does not happen if I just try to create a customer. As soon as I do `Facility facility = new Facility()` then I got that duplication (I explain about this a bit in coding toward the end of my post).
Harry Pham
Now comment `em.persistent(facility)` does not solve the problem. I still have the duplication, plus I got nothing insert into FACILITY table. However 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
Harry Pham