在双向JPA OneToMany / ManyToOne关联中,“关联的反面”是什么意思?

在TopLink JPA注释参考的这些例子中:

示例1-59 @OneToMany – 具有generics的客户类

@Entity public class Customer implements Serializable { ... @OneToMany(cascade=ALL, mappedBy="customer") public Set<Order> getOrders() { return orders; } ... } 

示例1-60 @ManyToOne – 带generics的订单类

 @Entity public class Order implements Serializable { ... @ManyToOne @JoinColumn(name="CUST_ID", nullable=false) public Customer getCustomer() { return customer; } ... } 

在我看来, Customer实体是协会的所有者。 但是,在同一个文档的mappedBy属性的解释中,写道:

如果关系是双向的,则将关联的反向(非拥有)一侧上的mappedBy元素设置为拥有该关系的字段或属性的名称,如示例1-60所示。

但是,如果我没有错,看起来就像在这个例子中, mappedBy实际上是在关联的拥有者一方指定的,而不是非拥有者一方。

所以我的问题基本上是:

  1. 在一个双向(一对多/多对一)关联中,哪个实体是所有者? 我们如何指定一方作为所有者? 我们如何指定多方为业主?

  2. 什么是“协会的反面”? 我们怎样才能把一方指定为逆? 我们怎么能把多方指定为逆?

要了解这一点,你必须退后一步。 在OO中,客户拥有订单(订单是客户对象中的清单)。 没有顾客就不可能有订单。 所以客户似乎是订单的所有者。

但是在SQL世界中,一个项目实际上将包含一个指向另一个的指针。 由于N个订单有1个客户,每个订单都包含它所属客户的外部关键字。 这是“连接”,这意味着命令“拥有”(或字面上包含)连接(信息)。 这与OO /模型世界完全相反。

这可能有助于了解:

 public class Customer { // This field doesn't exist in the database // It is simulated with a SQL query // "OO speak": Customer owns the orders private List<Order> orders; } public class Order { // This field actually exists in the DB // In a purely OO model, we could omit it // "DB speak": Order contains a foreign key to customer private Customer customer; } 

反面是对象的OO“拥有者”,在这种情况下是客户。 客户在表格中没有列来存储订单,所以您必须告诉它在订单表中的哪个地方可以保存这些数据(这是通过mappedBy发生的)。

令人难以置信的是,在3年之内,没有人用这两种方法来绘制这种关系的例子来回答你的优秀问题。

正如其他人所说,“所有者”一方在数据库中包含指针(外键)。 你可以指定任何一方作为所有者,但是,如果你指定一方作为所有者,那么这种关系就不是双向的(反过来,“多”方面也不知道它的“所有者”)。 这对于封装/松散耦合可能是理想的:

 // "One" Customer owns the associated orders by storing them in a customer_orders join table public class Customer { @OneToMany(cascade = CascadeType.ALL) private List<Order> orders; } // if the Customer owns the orders using the customer_orders table, // Order has no knowledge of its Customer public class Order { // @ManyToOne annotation has no "mappedBy" attribute to link bidirectionally } 

唯一的双向映射解决scheme是让“多”一侧拥有指向“一”的指针,并使用@OneToMany“mappedBy”属性。 没有“mappedBy”属性,Hibernate会期望一个双重映射(数据库将有连接列和连接表,这是冗余的(通常是不希望的))。

 // "One" Customer as the inverse side of the relationship public class Customer { @OneToMany(cascade = CascadeType.ALL, mappedBy = "customer") private List<Order> orders; } // "many" orders each own their pointer to a Customer public class Order { @ManyToOne private Customer customer; } 

数据库中具有外键的表的实体是拥有实体,而所指向的另一个表是逆实体。

简单的双向关系规则:

对于多对一的双向关系来说,多方面往往是关系的一面。 例如:1房间有很多人(一个人只属于一个房间) – >拥有方是Person

2.对于一对一的双向关系,拥有方对应于包含相应外键的一面。

对于多对多的双向关系来说,任何一方都可能是自己的一面。

希望可以帮助你。

对于两个实体类Customer和Order,hibernate将创build两个表。

可能的情况:

  1. 在Customer.java和Order.java类中不使用mappedBy> – >

    在客户端将创build一个新的表[名称= CUSTOMER_ORDER],这将保持CUSTOMER_ID和ORDER_ID的映射。 这些是客户和订单表的主键。 在订单一侧,需要额外的一列来保存相应的Customer_IDlogging映射。

  2. 在Customer.java中使用mappedBy [如问题陈述中给出]现在不会创build附加表[CUSTOMER_ORDER]。 订单表中只有一列

  3. mappedby在Order.java中使用现在,额外的表将由hibernate创build。[name = CUSTOMER_ORDER] Order Table不会有额外的[Customer_ID]列进行映射。

任何一方都可以成为关系的所有者。 但是最好selectxxxToOne方面。

编码效果 – >只有实体的所有者才能改变关系状态。 在下面的例子中,BoyFriend类是关系的所有者。 即使女朋友想分手,也不行。

 import javax.persistence.*; import java.util.ArrayList; import java.util.List; @Entity @Table(name = "BoyFriend21") public class BoyFriend21 { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "Boy_ID") @SequenceGenerator(name = "Boy_ID", sequenceName = "Boy_ID_SEQUENCER", initialValue = 10,allocationSize = 1) private Integer id; @Column(name = "BOY_NAME") private String name; @OneToOne(cascade = { CascadeType.ALL }) private GirlFriend21 girlFriend; public BoyFriend21(String name) { this.name = name; } public BoyFriend21() { } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public BoyFriend21(String name, GirlFriend21 girlFriend) { this.name = name; this.girlFriend = girlFriend; } public GirlFriend21 getGirlFriend() { return girlFriend; } public void setGirlFriend(GirlFriend21 girlFriend) { this.girlFriend = girlFriend; } } import org.hibernate.annotations.*; import javax.persistence.*; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.Table; import java.util.ArrayList; import java.util.List; @Entity @Table(name = "GirlFriend21") public class GirlFriend21 { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "Girl_ID") @SequenceGenerator(name = "Girl_ID", sequenceName = "Girl_ID_SEQUENCER", initialValue = 10,allocationSize = 1) private Integer id; @Column(name = "GIRL_NAME") private String name; @OneToOne(cascade = {CascadeType.ALL},mappedBy = "girlFriend") private BoyFriend21 boyFriends = new BoyFriend21(); public GirlFriend21() { } public GirlFriend21(String name) { this.name = name; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public GirlFriend21(String name, BoyFriend21 boyFriends) { this.name = name; this.boyFriends = boyFriends; } public BoyFriend21 getBoyFriends() { return boyFriends; } public void setBoyFriends(BoyFriend21 boyFriends) { this.boyFriends = boyFriends; } } import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import java.util.Arrays; public class Main578_DS { public static void main(String[] args) { final Configuration configuration = new Configuration(); try { configuration.configure("hibernate.cfg.xml"); } catch (HibernateException e) { throw new RuntimeException(e); } final SessionFactory sessionFactory = configuration.buildSessionFactory(); final Session session = sessionFactory.openSession(); session.beginTransaction(); final BoyFriend21 clinton = new BoyFriend21("Bill Clinton"); final GirlFriend21 monica = new GirlFriend21("monica lewinsky"); clinton.setGirlFriend(monica); session.save(clinton); session.getTransaction().commit(); session.close(); } } import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import java.util.List; public class Main578_Modify { public static void main(String[] args) { final Configuration configuration = new Configuration(); try { configuration.configure("hibernate.cfg.xml"); } catch (HibernateException e) { throw new RuntimeException(e); } final SessionFactory sessionFactory = configuration.buildSessionFactory(); final Session session1 = sessionFactory.openSession(); session1.beginTransaction(); GirlFriend21 monica = (GirlFriend21)session1.load(GirlFriend21.class,10); // Monica lewinsky record has id 10. BoyFriend21 boyfriend = monica.getBoyFriends(); System.out.println(boyfriend.getName()); // It will print Clinton Name monica.setBoyFriends(null); // It will not impact relationship session1.getTransaction().commit(); session1.close(); final Session session2 = sessionFactory.openSession(); session2.beginTransaction(); BoyFriend21 clinton = (BoyFriend21)session2.load(BoyFriend21.class,10); // Bill clinton record GirlFriend21 girlfriend = clinton.getGirlFriend(); System.out.println(girlfriend.getName()); // It will print Monica name. //But if Clinton[Who owns the relationship as per "mappedby" rule can break this] clinton.setGirlFriend(null); // Now if Monica tries to check BoyFriend Details, she will find Clinton is no more her boyFriend session2.getTransaction().commit(); session2.close(); final Session session3 = sessionFactory.openSession(); session1.beginTransaction(); monica = (GirlFriend21)session3.load(GirlFriend21.class,10); // Monica lewinsky record has id 10. boyfriend = monica.getBoyFriends(); System.out.println(boyfriend.getName()); // Does not print Clinton Name session3.getTransaction().commit(); session3.close(); } }