2

私はJPA 2.0を初めて使用し、関係を説明する追加の属性を持つ外部キークラスを使用する an:m 関係に注釈を付けるのに問題があります。

顧客は複数の雑誌を購読できます。すべての雑誌Subscriptionは正確に 1 対 1 で作成されCustomerMagazineさらに購読期間を節約できます。

これが私の注釈付きクラスです。フィールドアクセスを使用しています。コンストラクター、セッター、ゲッター (注釈なし)、およびメソッドなどのボイラープレート コードを省略toStringequalsまし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          |
+-----------------------+

3 つのテーブルのみで、customer内容magazinesubscription次のとおりです。

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

2 つのテーブルcustomer_subscriptionmagazine_subscription空のままです。しかし、私が見たところ、それらは必要でさえありません-他の3つのテーブルは、私が望んでいたのとまったく同じように見えます. だから私の質問は:

この例で使用されている m:n 関係を JPA 2.0 で正しくモデル化するには、余分なテーブルを作成せずに、雑誌または顧客のすべての購読を読み書きする機能を保持するにはどうすればよいでしょうか?

誰かがコードに興味を持っている場合に備えて、ここにアップロードしました: http://goo.gl/qSc2e ; localhost のポート 3306 で実行されている「kiosk」という名前の MySQL 5 データベースが必要です。ルート パスワードは空です。

4

2 に答える 2

2

モデルには、実際には多対多の関係はありません。

CustomertoSubscriptionは 1 対多です。 MagazinetoSubscriptionは 1 対多です。

これをエンティティモデルとして試してください:

@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 は冗長なリンク テーブルを生成しません。

于 2012-04-10T17:27:03.340 に答える
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;

    // ..
}

5 つではなく、(必要に応じて) 3 つのテーブルのみを作成します。

于 2012-04-11T10:12:16.047 に答える