2012-09-10 36 views
5

Tôi đã kiểm tra nhiều bài đăng trên internet và không có vấn đề gì về vấn đề của tôi. Thực sự đánh giá cao nếu có ai có thể giúp! Tôi có mối quan hệ cha mẹ con OneToMany. Hibernate không ghép tầng chèn con (Level2) khi một trong các khóa tổng hợp con là khóa ngoài cho cấp độ gốc (Cấp độ 1). Tôi chỉ định cascade = "tất cả" và không có vấn đề nghịch đảo là đúng hay sai, kết quả là như nhau. Không có ngoại lệ, và nó chỉ đơn giản là không chèn. Dưới đây in ra cho thấy Level1 đã được chèn thành công nhưng Level2 chỉ được chọn, không chèn.Không có chèn tầng cho con với khóa nước ngoài trên cha mẹ

Hibernate: chèn vào sst.level_1 (STATUS, NAME) giá trị Hibernate (,?): Chọn level2x_.LEVEL_1_ID, level2x_.TIMESEGMENT, level2x_.CATEGORY như CATEGORY4_ từ sst.level_2 level2x_ nơi level2x_.LEVEL_1_ID =? và level2x_.TIMESEGMENT =?

API được Hibernate 4.1.6/Spring 3.1.2.

Dưới đây là định nghĩa bảng cho mySQL:

CREATE TABLE level_1 
(
ID int NOT NULL PRIMARY KEY AUTO_INCREMENT, 
STATUS int, 
NAME varchar(255) 
); 

CREATE TABLE level_2 
(
LEVEL_1_ID int, 
TIMESEGMENT int, 
CATEGORY varchar(2), 
PRIMARY KEY (LEVEL_1_ID, TIMESEGMENT), 
FOREIGN KEY (LEVEL_1_ID) REFERENCES level_1(ID) ON DELETE CASCADE 
); 

Đây là mã kiểm tra.

public class Test { 

    public static void main(String[] args) { 
     ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); 
     doInsert(context); 
    } 

    private static void doInsert(ApplicationContext context) { 

     Level1 level1 = new Level1(); 
     Level2 level2 = new Level2(); 

     level1.setName("LEVEL 1 NAME"); 
     level1.setStatus(1); 
     level1.getLevel2s().add(level2); 

     level2.setLevel1(level1); 
     level2.setCategory("CA"); 
     level2.setId(new Level2Id(level1.getId(), 10)); 

     Level1DAO level1DAO = (Level1DAO) context.getBean("Level1DAO"); 
     level1DAO.save(level1); 
    } 
} 

Mapping cho Level1:

<hibernate-mapping> 
    <class name="com.jc.hibernate.Level1" table="level_1" catalog="sst"> 
     <id name="id" type="java.lang.Integer"> 
      <column name="ID" /> 
      <generator class="identity" /> 
     </id> 
     <property name="status" type="java.lang.Integer"> 
      <column name="STATUS" /> 
     </property> 
     <property name="name" type="java.lang.String"> 
      <column name="NAME" /> 
     </property> 
     <set name="level2s" inverse="true" cascade="all"> 
      <key> 
       <column name="LEVEL_1_ID" not-null="true" /> 
      </key> 
      <one-to-many class="com.jc.hibernate.Level2" /> 
     </set> 
    </class> 
</hibernate-mapping> 

Mapping cho level2:

<hibernate-mapping> 
    <class name="com.jc.hibernate.Level2" table="level_2" catalog="sst"> 
     <composite-id name="id" class="com.jc.hibernate.Level2Id"> 
      <key-property name="level1Id" type="java.lang.Integer"> 
       <column name="LEVEL_1_ID" /> 
      </key-property> 
      <key-property name="timesegment" type="java.lang.Integer"> 
       <column name="TIMESEGMENT" /> 
      </key-property> 
     </composite-id> 
     <many-to-one name="level1" class="com.jc.hibernate.Level1" update="false" insert="false" fetch="select"> 
      <column name="LEVEL_1_ID" not-null="true" /> 
     </many-to-one> 
     <property name="category" type="java.lang.String"> 
      <column name="CATEGORY" length="2" /> 
     </property> 
    </class> 
</hibernate-mapping> 

Trả lời

1

lập bản đồ của bạn có vẻ là đúng.

Vấn đề của bạn trông giống như là dòng

level2.setId(new Level2Id(level1.getId(), 10)); 

Khi dòng này được thực thi, các level1 vẫn không có id của nó được gán cho nó, vì vậy nó sẽ là null. Là level_1_id và phân khúc là khóa chính hỗn hợp, không có khóa nào trong số đó có thể là rỗng. Vì vậy, bạn sẽ cần phải làm đầu tiên

Integer generatedId = (Integer) Session.save(level1) 

này làm một chèn ngay lập tức trong cơ sở dữ liệu và trả về nhận dạng. Sau đó, bạn có thể sử dụng định danh để tạo Lever2Id

level2.setId(new Level2Id(generatedId , 10)); 

Tôi cố gắng này trên MySql với ánh xạ mà bạn cung cấp và làm việc tốt của nó.

Nếu tôi không đầu tiên lưu level1 đầu tiên, nó mang lại cho tôi lỗi

Column 'LEVEL_1_ID' cannot be null 

CẬP NHẬT

Đáng tiếc là nó trông giống như thác không hoạt động tự động khi có phím composite ở trẻ em và một trong các cột trong khóa tổng hợp đề cập đến khóa chính của cấp độ gốc. Vì vậy, bạn phải thiết lập các id và quan hệ theo cách thủ công như được hiển thị ở trên. Lưu ý rằng nếu đứa trẻ có một id cột duy nhất và quan hệ của bạn là một đến một thì Hibernate có thể tìm ra rằng cột con chính xuất phát từ Parent và có thể thiết lập tự động.Xem herehere

Các tài liệu quá đề nghị này here

“Bạn không thể sử dụng một IdentifierGenerator để tạo ra các phím composite. Thay vào đó, ứng dụng phải gán định danh riêng của mình.”

Lớp ngủ đông đại diện cho lập bản đồ id composit là org.hibernate.mapping.Component (được sử dụng cho thành phần, thành phần composite, nhận dạng composite, vv) và mặc định Chiến lược tạo id được "gán" trừ khi bạn đã cung cấp trình tạo id tùy chỉnh sẽ đưa bạn đến một cách hackish bằng cách tạo CompositeUserType của riêng bạn (cho ID tổng hợp) và sử dụng trình tạo Định danh tùy chỉnh như đã đề cập here. Nhưng điều này có vẻ xấu xí và quá mức cần thiết.

Về lưu cả cha và con và thiết lập quan hệ theo cách thủ công trong giao dịch Đầu tiên loại bỏ tùy chọn thác tất cả từ phần tử Cài đặt gốc hoặc đặt thành "không", sao cho không có sự tồn tại liên tục của Hibernate. Lưu cha mẹ sẽ chỉ lưu phụ huynh và không phải là con.

Sau đó chuẩn bị Cha mẹ và Trẻ em với tất cả các thuộc tính bạn có sẵn và đặt quan hệ đối tượng từ cả hai mặt như thế này (để đảm bảo tính nhất quán của mô hình). phương pháp addChild

Parent parent = new Parent(); 
    parent.setStatus(1 ); 
    parent.setName("Parent"); 
    ChildId childId = new ChildId();  
    Child child = new Child(childId);  
    child.setCategory("TH");  
    parent.addChild(child); 
    child.getId().setTimesegment(10); 

của phụ huynh cho biết thêm con để bộ sưu tập cũng như thiết lập là cha mẹ đứa trẻ trong một phương pháp thuận tiện

public void addChild(Child child){ 
    if (child !=null){ 
     getChildrens().add(child); 
     child.setParent(this); 
    } 

    } 

Sau đó, để có một phương pháp trong DAO mà mất con như tham số và cũng là giao dịch, một cái gì đó như thế này (mặc dù cách tốt hơn là làm cho lớp dịch vụ giao dịch thay vì lớp DAO)

public void save(Child child){ 

    //get Session 
    Session session =....... 
    Transaction tx = session.beginTransaction(); 
    Integer generatedId = (Integer)session.save(child.getParent()); 
    ChildId childId = child.getId(); 
    childId.setChildId(generatedId);  
    session1.save(child); 
    tx1.commit(); 
    HibernateUtil.closeSession(); 
} 

Hiện tại đây là những gì tôi có thể đề xuất.

+0

Cảm ơn bạn đã trả lời. Nó có nghĩa là id cấp 1 là null, gây ra vấn đề. Trong trường hợp này, làm thế nào tôi cấu hình giao dịch để làm cho nó nguyên tử cho cấp 1 và 2? – John

+0

Xem nội dung cập nhật của tôi để lưu cả trẻ em và cha mẹ trong giao dịch – Shailendra

0

Chỉ cần cập nhật. Tôi đã xóa id tổng hợp. Thay vào đó, hãy sử dụng khóa thay thế do cơ sở dữ liệu tạo trên bảng con và khóa ngoài cho id cha. Điều này làm việc với một đến nhiều mối quan hệ với cascade = "all". Lưu phụ huynh lưu con trong một bước. Điều này không giải quyết được câu hỏi ban đầu, mà là một giải pháp thay thế.

CREATE TABLE level_11 (
ID int NOT NULL PRIMARY KEY AUTO_INCREMENT, 
STATUS int, NAME varchar(255)); 

CREATE TABLE level_22 (ID int NOT NULL PRIMARY KEY AUTO_INCREMENT, 
LEVEL_11_ID int NOT NULL, 
TIMESEGMENT int NOT NULL, 
FOREIGN KEY (LEVEL_11_ID) REFERENCES level_11(ID) ON DELETE CASCADE, 
CONSTRAINT UQ_LEVEL2 UNIQUE (LEVEL_11_ID, TIMESEGMENT)); 
Các vấn đề liên quan