2016-04-25 34 views
1

我有,我很高興與現有的數據模型:使用JPA註解使用Hibernate來形容@OneToMany關係,其中外鍵只在子表

public class Garden { 
    private String name; // "Oak Grove" 
    private List<Plant> plants; 
} 

public class Plant { 
    private String name; // "Cherry Tomato" 
} 

我想在Hibernate中映射此符合下列條件:

  1. Plant類在Java中不維護其父Garden參考。這使得Java層,IMO中的事情變得更加困難。

  2. PLANT表應該有一個GARDEN_ID列,它是GARDEN(ID)列的外鍵。

我的初始設置中,除了@OneToMany之前:

@Entity(name = "GARDEN") 
public class Garden { 
    @Id 
    @Column(name = "ID", nullable = false) 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 

    @Column(name = "NAME", nullable = false) 
    private String name; // "Oak Grove" 

    // Not yet mapped 
    private List<Plant> plants; 
} 

@Entity(name = "PLANT") 
public class Plant { 
    @Id 
    @Column(name = "ID", nullable = false) 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 

    @Column(name = "NAME", nullable = false) 
    private String name; // "Cherry Tomato" 
} 

我怎麼能以這樣的方式外鍵參考保持在Plant定義的List<Plant> plants;@OneToMany註解?

如果我再補充:

@OneToMany(cascade = { CascadeType.ALL }) 
@JoinColumn(name = "GARDEN_ID") 
private List<Plant> plants; 

然後保存與植物花園未能像這樣:

Caused by: org.h2.jdbc.JdbcSQLException: NULL not allowed for column "GARDEN_ID"; SQL statement: 
insert into PLANT (NAME, ID) values (?, ?) [23502-191] 

如此看來休眠是不是要堅持外鍵。有沒有辦法做到這一點,而不是完全扼殺我的對象模型?

編輯:我測試這一問題的方法是:

Garden garden = new Garden("Oak Grove"); 
garden.addPlant(new Plant("Cherry Tomato")); 
gardenManager.save(garden); 

其中save()方法看起來非常休眠安永:

public void save(T item) { 
    try (Session session = factory.openSession()) { 
     Transaction transaction = session.beginTransaction(); 
     try { 
      session.saveOrUpdate(item); 
      transaction.commit(); 
     } catch (Exception ex) { 
      System.out.println("Error occurred saving item: " + ex.getMessage()); 
      ex.printStackTrace(); 
      transaction.rollback(); 
     } 
    } 
} 
+0

你有沒有嘗試刪除@JoinColumn和添加的mappedBy到@OneToMany?@OneToMany(cascade = CascadeType.ALL, mappedBy =「garden」) – RubioRic

+0

@Nicholas Code添加。 –

+0

@RubioRic這是我的理解是,'mappedBy'是在孩子('Plant')類上有相應的Java屬性('private Garden garden')時使用的 - 這不是我想要完成的。 –

回答

2

Yogesh Sakurikar接近,但雙向@JoinColumn是有點關閉。下面您將看到如何加入雙向或單向

@Entity(name = "GARDEN") 
public class Garden { 
    @Id 
    @Column(name = "ID", nullable = false) 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 

    @Column(name = "NAME", nullable = false) 
    private String name; // "Oak Grove" 

    // use this if you don't want a bi-directional relationship 
    // @OneToMany 
    // @JoinColumn(name = "ID", referencedColumnName="GARDEN_ID") 
    // private List<Plant> plants; 

    // use this if you want it bi-directional 
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "garden") 
    private Set<Plant> plants; 
} 

@Entity(name = "PLANT") 
public class Plant { 
    @Id 
    @Column(name = "ID", nullable = false) 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 

    @Column(name = "NAME", nullable = false) 
    private String name; // "Cherry Tomato" 

    // use this if you don't want a bi-directional relationship 
    // @Column(name="GARDEN_ID") 
    // private long gardenId; 

    // use this if you want a bi-directional relationship 
    @ManyToOne 
    @JoinColumn(name = "GARDEN_ID", referencedColumnName="ID", nullable = false) 
    private Garden garden; 

} 

下面的代碼假設爲雙向關係。否則,你需要知道你的Garden.id之前,你可以完整地描述任何一個孩子Plant

Garden garden = new Garden("Oak Grove"); 
Plant plant = new Plant("Cherry Tomato") 
plant.setGarden(garden); //don't forget to set the parent on the child 
garden.addPlant(plant); 
gardenManager.save(garden); 
+0

問題是我寧願'植物'不瞭解'花園'。否則,我需要「不要忘記」的代碼位,我覺得有點麻煩。我認爲對象模型層不應該爲滿足數據庫做出犧牲 - 相反,它應該處理數據。 –

+0

然後你需要一個單獨的鏈接表。 –

+0

將父母設置爲孩子實際上是「更清潔」的方法,因爲您不需要知道任何一方的ID。你的需求會增加一個第三個表(你應該有第三個實體),其中'@ OneToOne'包含'Plant'和'@ ManyToOne'包含'Gadren' ...除非你想要相同的'Plant'在多個'Garden'中,這會使它們成爲'@ ManyToMany',然後DEFINITELY需要一個連接表。 –

1

對一對多的關係,如果該工廠將保持這種關係,您需要使用雙向定義它。 這裏是我認爲你應該能夠實現它:

@Entity(name = "GARDEN") 
public class Garden { 
    @Id 
    @Column(name = "ID", nullable = false) 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 

    @Column(name = "NAME", nullable = false) 
    private String name; // "Oak Grove" 

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "garden") 
    private List<Plant> plants; 
} 

@Entity(name = "PLANT") 
public class Plant { 
    @Id 
    @Column(name = "ID", nullable = false) 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 

    @Column(name = "NAME", nullable = false) 
    private String name; // "Cherry Tomato" 

    @ManyToOne 
    @JoinColumn(name = "GARDEN_ID", nullable = false) 
    Garden garden; 
} 

這種雙向的做法將讓實體管理器知道存在着兩者之間的關係,因爲在一個方面,它是一對多的,爲對方它變成了多對一。希望這會有所幫助。

+0

我很欣賞答案,但我正在尋找一種方法來映射當前對象模型而不需要在「植物」中添加一個「花園」。 –

+0

不知道這是否有幫助,但我也會試試這個:@OneToMany(cascade = CascadeType.ALL) @JoinTable(name =「PLANT」,joinColumns = {@ JoinColumn(name =「GARDEN_ID」,referencedColumnName =「 ID「)} ,inverseJoinColumns = {@ JoinColumn(name =」ID「,referencedColumnName =」GARDEN_ID「)}) private設置植物; –