开发者

Persistence a One-To-Many Relationship

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. 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜