我是JPA 2.0的新手,并且在使用外键类以及描述关系的其他属性的n:m关系中注释时遇到了麻烦:
客户可以订阅多个杂志,每Subscription
只创建一个Customer
和一个Magazine
,另外还可以保存订阅的持续时间。
这是我的注释类,我正在使用字段访问。我省略了一些样板代码,如构造函数,setter,getter(未注释)和方法toString
,equals
和hashCode
。
@Entity
public class Customer {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToMany
private Set<Subscription> subscriptions;
// ..
}
@Entity
public class Magazine {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToMany
private Set<Subscription> subscriptions;
// ..
}
@Entity
public class Subscription {
private Date start;
private Date end;
@EmbeddedId
private SubscriptionId id;
// ..
}
@Embeddable
public class SubscriptionId implements Serializable {
@ManyToOne
private Customer customer;
@ManyToOne
private Magazine magazine;
// ..
}
我通过创建和持久保存一些对象来测试我的注释,如下所示:
public static void main(String[] args) {
EntityManagerFactory emf = Persistence
.createEntityManagerFactory("kiosk");
EntityManager em = emf.createEntityManager();
persist(em);
em.close();
emf.close();
}
private static void persist(EntityManager em) {
em.getTransaction().begin();
Magazine mag1 = new Magazine("mag1");
Magazine mag2 = new Magazine("mag2");
Customer cus1 = new Customer("cus1");
Customer cus2 = new Customer("cus2");
Customer cus3 = new Customer("cus3");
Subscription sub1 = new Subscription(cus1, mag1);
Subscription sub2 = new Subscription(cus2, mag1);
Subscription sub3 = new Subscription(cus2, mag2);
Subscription sub4 = new Subscription(cus3, mag2);
em.persist(mag1);
em.persist(mag2);
em.persist(cus1);
em.persist(cus2);
em.persist(cus3);
em.persist(sub1);
em.persist(sub2);
em.persist(sub3);
em.persist(sub4);
em.getTransaction().commit();
}
提供程序创建以下MySQL数据库:
mysql> show tables;
+-----------------------+
| Tables_in_kiosk |
+-----------------------+
| customer |
| customer_subscription |
| magazine |
| magazine_subscription |
| subscription |
+-----------------------+
只有三个表customer
,magazine
和subscription
才有内容:
mysql> select * from customer;
+-------------+------+
| customer_id | name |
+-------------+------+
| 1 | cus1 |
| 2 | cus2 |
| 3 | cus3 |
+-------------+------+
mysql> select * from magazine;
+-------------+------+
| magazine_id | name |
+-------------+------+
| 1 | mag1 |
| 2 | mag2 |
+-------------+------+
mysql> select * from subscription;
+------+-------+-------------+-------------+
| end | start | magazine_id | customer_id |
+------+-------+-------------+-------------+
| NULL | NULL | 1 | 1 |
| NULL | NULL | 1 | 2 |
| NULL | NULL | 2 | 2 |
| NULL | NULL | 2 | 3 |
+------+-------+-------------+-------------+
如果我知道他们的钥匙,我可以阅读我的订阅。我还没有尝试过阅读整套客户或杂志。
private static void find(EntityManager em) {
Magazine mag1 = em.find(Magazine.class, 1L);
Magazine mag2 = em.find(Magazine.class, 2L);
Customer cus1 = em.find(Customer.class, 1L);
Customer cus2 = em.find(Customer.class, 2L);
Customer cus3 = em.find(Customer.class, 3L);
Subscription sub1 = em.find(Subscription.class, new SubscriptionId(cus1, mag1));
Subscription sub2 = em.find(Subscription.class, new SubscriptionId(cus2, mag1));
Subscription sub3 = em.find(Subscription.class, new SubscriptionId(cus2, mag2));
Subscription sub4 = em.find(Subscription.class, new SubscriptionId(cus3, mag2));
System.out.println(mag1);
System.out.println(mag2);
System.out.println(cus1);
System.out.println(cus2);
System.out.println(cus3);
System.out.println(sub1);
System.out.println(sub2);
System.out.println(sub3);
System.out.println(sub4);
}
打印:
Magazine [id=1, name=mag1, subscriptions=null]
Magazine [id=2, name=mag2, subscriptions=null]
Customer [id=1, name=cus1, subscriptions=null]
Customer [id=2, name=cus2, subscriptions=null]
Customer [id=3, name=cus3, subscriptions=null]
Subscription [start=null, end=null, id=SubscriptionId [customer=1, magazine=1]]
Subscription [start=null, end=null, id=SubscriptionId [customer=2, magazine=1]]
Subscription [start=null, end=null, id=SubscriptionId [customer=2, magazine=2]]
Subscription [start=null, end=null, id=SubscriptionId [customer=3, magazine=2]]
两个表格customer_subscription
和magazine_subscription
仍为空。但是,正如我所看到的,它们甚至不是必需的 - 其他3个表看起来就像我想要的那样。所以我的问题是:
如何正确建模此示例中使用的m:n关系与JPA 2.0,而不创建多余的表,同时保留编写和阅读杂志或客户的所有订阅的能力?
如果有人对代码感兴趣,我已在此处上传:http://goo.gl/qSc2e;你需要一个名为“kiosk”的MySQL 5数据库,它运行在localhost上的端口3306,并带有一个空的root密码。
答案 0 :(得分:2)
您的模型实际上没有任何多对多关系。
Customer
到Subscription
是一对多的。
Magazine
到Subscription
是一对多的。
尝试将此作为您的实体模型:
@Entity
public class Customer {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany
private Set<Subscription> subscriptions;
// ..
}
@Entity
public class Magazine {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany
private Set<Subscription> subscriptions;
// ..
}
@Entity
public class Subscription {
private Date start;
private Date end;
@EmbeddedId
private SubscriptionId id;
// ..
}
@Embeddable
public class SubscriptionId implements Serializable {
@ManyToOne
private Customer customer;
@ManyToOne
private Magazine magazine;
// ..
}
并且Hibernate不会生成冗余链接表。
答案 1 :(得分:1)
milkplusvellocetless的答案是解决方案的一部分,在mappedBy
注释中添加@OneToMany
属性可以解决问题:
@Entity
public class Magazine {
@Id
@GeneratedValue
private Long id;
@NotNull
private String name;
@OneToMany(mappedBy = "id.magazine")
private Set<Subscription> subscriptions;
// ..
}
@Entity
public class Customer {
@Id
@GeneratedValue
private Long id;
@NotNull
private String name;
@OneToMany(mappedBy = "id.customer")
private Set<Subscription> subscriptions;
// ..
}
@Entity
public class Subscription {
private Date start;
private Date end;
@EmbeddedId
private SubscriptionId id;
// ..
}
@Embeddable
public class SubscriptionId implements Serializable {
@ManyToOne
private Customer customer;
@ManyToOne
private Magazine magazine;
// ..
}
仅创建3个表(按照需要)而不是5个。