双方向一対多(多対一)@OneToManyまたは@ManyToOneの使い方
9204 ワード
例えば、一例を用いて、JPAの一対多と多対一の学習を開始します.
例えば、ネットで本を買うと、ネットで注文します.
上記のビジネス・アクティビティの説明から、1つの注文に1つ以上の注文項目を含めることができます.では、注文と注文項目の設計関係を(1:N)一対多の関係(0を除く)にします.関係が出たらJPAを使ってこの関係を実現します(JPAの設立と基本的な構成についてはもう言わないで、分からないなら見てください
JPA入門編).
まず、受注エンティティクラスを作成します.
受注項目のエンティティークラス
テストクラスを見てみましょう
双方向の一対の多関係、一つは関係維持端(owner side)、多くは関係被維持端(inverse side)である.関係が維持される側では、@JoinColumnによって外部キー列が関係維持側を指すプライマリ・キー列を確立する必要があります.
publicclass
Order
implements
Serializable {
private
Set orderItems
=
new
HashSet();
....
@
OneToMany
(mappedBy=
"order"
,cascade = CascadeType.
ALL
, fetch = FetchType.
LAZY
)
@
OrderBy
(value =
"id ASC"
)
public
Set getOrderItems() {
return
orderItems
;
}
}
publicclass
OrderItem
implements
Serializable {
private
Order
order
;
....
@
ManyToOne
(cascade=CascadeType.
REFRESH
,optional=
false
)
@
JoinColumn
(name =
"order_id"
)
public
Order getOrder() {
return
order
;
}
}
@OrderBy(value = "id ASC")
ロードの指定
OrderItem
を押します.
id
の昇順ソート
@OneToMany
のプロパティ
:
1>targetEntity
リレーショナル・クラスのタイプを定義します.デフォルトはメンバー・プロパティに対応するクラス・タイプです.したがって、通常は定義は必要ありません.
2>mappedBy
クラス間の双方向関係を定義します.クラス間が一方向関係である場合、定義を提供する必要はありません.クラスとクラスの間に双方向関係が形成されている場合、この属性を使用して定義する必要があります.そうしないと、データの一貫性の問題を引き起こす可能性があります.
この属性の値は「マルチ」方classの「一」方の変数名です.
3>cascade
このプロパティは、クラスとクラス間のカスケード関係を定義します.定義されたカスケード関係は、コンテナによって現在のクラスオブジェクトとその関連クラスオブジェクトに対して同じ操作が行われ、この関係は再帰的に呼び出されると見なされます.例を挙げます.
Order
および
OrderItem
カスケード関係がある場合は削除
Order
を選択すると、対応する
OrderItem
オブジェクト.もし
OrderItem
他のオブジェクトとカスケード関係がある場合、このような操作は常に再帰的に実行されます.
cascade
の値は
CascadeType.PERSIST
(カスケード新規)、
CascadeType.REMOVE
(カスケード削除)、
CascadeType.REFRESH
(カスケード・リフレッシュ)、
CascadeType.MERGE
(カスケード更新)で1つ以上を選択します.もう一つの選択肢は
CascadeType.ALL
を選択します.
4>fatch
選択できる項目は次のとおりです.
FetchType.EAGER
および
FetchType.LAZY
.前者は関係クラスを表す
(
この例は
OrderItem
クラス#クラス#
)
プライマリクラス
(
この例は
Order
クラス#クラス#
)
ロード時に同時にロードされます.後者は、リレーショナル・クラスがアクセスされたときにロードされることを示します.デフォルトは
FetchType.LAZY
.
@JoinColumn(name = "order_id")
注記OrderItemマッピングテーブルのorder_を指定するid列は外部キーとしてOrderマッピングテーブルのプライマリキー列に関連付けられる.
@ManyToOne
:OrderItemとOrderの間に複数対1の関係があることを示します.
@ManyToOne
注記:targetEntity、cascade、fetch、optionalの4つの属性があり、最初の3つの属性の具体的な意味は@OneToManyの同名属性と同じであるが、@ManyToOneのfetch属性のデフォルト値はFetchTypeである.EAGER.
optional
プロパティは、関連クラスが存在する必要があるかどうかを定義し、値がfalseの場合、関連クラスの両方が存在する必要があります.関係が維持されていない場合、クエリーの結果はnullです.値がtrueの場合、リレーショナル・メンテナンス・エンドは存在しなくてもよいし、クエリーの結果はリレーショナル・メンテナンス・エンドに戻り、リレーショナル・メンテナンス・エンドでリレーショナル・メンテナンス・エンドを指す属性はnullになります.optionalプロパティのデフォルト値はtrueです.optionalプロパティは、実際には、optional=falseの場合joinクエリー関係がinner join、optional=trueの場合joinクエリー関係がleft joinなど、関連クラスと関連付けられたクラスのjoinクエリー関係を指定します.次のコード・スライスは、次のように説明されます.
ビジネス・メソッドがエンティティを
Bean
パラメータとしてクライアントに返す場合、エンティティを除く
Bean
自分で叶えたい
Serializable
インタフェース外
関連付けられたクラス(OrderItem)が遅延ロードの場合、エンティティBeanに戻る前に関連付けられたクラスにアクセスすることによって関連付けられたクラスをロードする必要があります(次の例を参照).そうでない場合、クライアントが関連クラスにアクセスすると、ロード例外が放出されます.
public
Order getOrderByID(Integer orderid) {
Order order =
em
.find(Order.
class
, orderid);
//!!!!!
遅延ロードなので実行
size()
この方法で受注のすべての受注項目を取得します.
order.getOrderItems().size();
return
order;
}
また、遅延ロードの有無にかかわらずjoin fetch関連文により関連クラスを明示的にロードできます.
次の例を示します.
public
List getAllOrder() {
Query query =
em
.createQuery(
"select DISTINCT o from Order o inner
join fetch o.orderItems order by o.orderid"
);
List result = query.getResultList();
return
result;
}
変換元:
http://blog.csdn.net/gebitan505/article/details/22619175http://blog.csdn.net/lxl_family/article/details/26523757
例えば、ネットで本を買うと、ネットで注文します.
上記のビジネス・アクティビティの説明から、1つの注文に1つ以上の注文項目を含めることができます.では、注文と注文項目の設計関係を(1:N)一対多の関係(0を除く)にします.関係が出たらJPAを使ってこの関係を実現します(JPAの設立と基本的な構成についてはもう言わないで、分からないなら見てください
JPA入門編).
まず、受注エンティティクラスを作成します.
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name="orders")
public class Order {
private String orderid;
private Float amount = 0f;
private Set items = new HashSet();
@Id
@Column(length = 12)
public String getOrderid() {
return orderid;
}
public void setOrderid(String orderid) {
this.orderid = orderid;
}
@Column(nullable = false)
public Float getAmount() {
return amount;
}
public void setAmount(Float amount) {
this.amount = amount;
}
@OneToMany(cascade = { CascadeType.REFRESH, CascadeType.PERSIST,CascadeType.MERGE, CascadeType.REMOVE },mappedBy ="order") // , 。mappBy , 。 OneToMany 。 Many,
public Set getItems() {
return items;
}
public void setItems(Set items) {
this.items = items;
}
/**
* order order
/*
public void addOrderItem(OrderItem orderItem){
orderItem.setOrder(this);//
this.items.add(orderItem);
}
}
受注項目のエンティティークラス
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
@Entity
public class OrderItem {
private Integer id;
private String productName;
private Float sellPrice = 0f;
private Order order;
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(length = 40, nullable = false)
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
@Column(nullable = false)
public Float getSellPrice() {
return sellPrice;
}
public void setSellPrice(Float sellPrice) {
this.sellPrice = sellPrice;
}
@ManyToOne(cascade = {CascadeType.MERGE,CascadeType.REFRESH }, optional = true)
@JoinColumn(name="order_id")// JoinColum , orderItem
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
}
テストクラスを見てみましょう
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.junit.BeforeClass;
import org.junit.Test;
import cn.itcast.bean.Order;
import cn.itcast.bean.OrderItem;
public class OneToManyTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
@Test public void addOrder(){
EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
EntityManager em = factory.createEntityManager();
em.getTransaction().begin(); // start transaction
Order order = new Order();
order.setAmount(34f);
order.setOrderid("00001");
//order OrderItem OrderItem1,OrderItem2
OrderItem orderItem1 = new OrderItem();
orderItem1.setProductName(" ");
orderItem1.setSellPrice(22f);
order.addOrderItem(orderItem1); //add orderitem in order
OrderItem orderItem2 = new OrderItem();
orderItem2.setProductName(" ");
orderItem2.setSellPrice(100f);
order.addOrderItem(orderItem2);
em.persist(order); //persist order object
em.getTransaction().commit(); //commit transaction
em.close();
factory.close();
}
}
双方向の一対の多関係、一つは関係維持端(owner side)、多くは関係被維持端(inverse side)である.関係が維持される側では、@JoinColumnによって外部キー列が関係維持側を指すプライマリ・キー列を確立する必要があります.
publicclass
Order
implements
Serializable {
private
Set orderItems
=
new
HashSet();
....
@
OneToMany
(mappedBy=
"order"
,cascade = CascadeType.
ALL
, fetch = FetchType.
LAZY
)
@
OrderBy
(value =
"id ASC"
)
public
Set getOrderItems() {
return
orderItems
;
}
}
publicclass
OrderItem
implements
Serializable {
private
Order
order
;
....
@
ManyToOne
(cascade=CascadeType.
REFRESH
,optional=
false
)
@
JoinColumn
(name =
"order_id"
)
public
Order getOrder() {
return
order
;
}
}
@OrderBy(value = "id ASC")
ロードの指定
OrderItem
を押します.
id
の昇順ソート
@OneToMany
のプロパティ
:
1>targetEntity
リレーショナル・クラスのタイプを定義します.デフォルトはメンバー・プロパティに対応するクラス・タイプです.したがって、通常は定義は必要ありません.
2>mappedBy
クラス間の双方向関係を定義します.クラス間が一方向関係である場合、定義を提供する必要はありません.クラスとクラスの間に双方向関係が形成されている場合、この属性を使用して定義する必要があります.そうしないと、データの一貫性の問題を引き起こす可能性があります.
この属性の値は「マルチ」方classの「一」方の変数名です.
3>cascade
このプロパティは、クラスとクラス間のカスケード関係を定義します.定義されたカスケード関係は、コンテナによって現在のクラスオブジェクトとその関連クラスオブジェクトに対して同じ操作が行われ、この関係は再帰的に呼び出されると見なされます.例を挙げます.
Order
および
OrderItem
カスケード関係がある場合は削除
Order
を選択すると、対応する
OrderItem
オブジェクト.もし
OrderItem
他のオブジェクトとカスケード関係がある場合、このような操作は常に再帰的に実行されます.
cascade
の値は
CascadeType.PERSIST
(カスケード新規)、
CascadeType.REMOVE
(カスケード削除)、
CascadeType.REFRESH
(カスケード・リフレッシュ)、
CascadeType.MERGE
(カスケード更新)で1つ以上を選択します.もう一つの選択肢は
CascadeType.ALL
を選択します.
4>fatch
選択できる項目は次のとおりです.
FetchType.EAGER
および
FetchType.LAZY
.前者は関係クラスを表す
(
この例は
OrderItem
クラス#クラス#
)
プライマリクラス
(
この例は
Order
クラス#クラス#
)
ロード時に同時にロードされます.後者は、リレーショナル・クラスがアクセスされたときにロードされることを示します.デフォルトは
FetchType.LAZY
.
@JoinColumn(name = "order_id")
注記OrderItemマッピングテーブルのorder_を指定するid列は外部キーとしてOrderマッピングテーブルのプライマリキー列に関連付けられる.
@ManyToOne
:OrderItemとOrderの間に複数対1の関係があることを示します.
@ManyToOne
注記:targetEntity、cascade、fetch、optionalの4つの属性があり、最初の3つの属性の具体的な意味は@OneToManyの同名属性と同じであるが、@ManyToOneのfetch属性のデフォルト値はFetchTypeである.EAGER.
optional
プロパティは、関連クラスが存在する必要があるかどうかを定義し、値がfalseの場合、関連クラスの両方が存在する必要があります.関係が維持されていない場合、クエリーの結果はnullです.値がtrueの場合、リレーショナル・メンテナンス・エンドは存在しなくてもよいし、クエリーの結果はリレーショナル・メンテナンス・エンドに戻り、リレーショナル・メンテナンス・エンドでリレーショナル・メンテナンス・エンドを指す属性はnullになります.optionalプロパティのデフォルト値はtrueです.optionalプロパティは、実際には、optional=falseの場合joinクエリー関係がinner join、optional=trueの場合joinクエリー関係がleft joinなど、関連クラスと関連付けられたクラスのjoinクエリー関係を指定します.次のコード・スライスは、次のように説明されます.
ビジネス・メソッドがエンティティを
Bean
パラメータとしてクライアントに返す場合、エンティティを除く
Bean
自分で叶えたい
Serializable
インタフェース外
関連付けられたクラス(OrderItem)が遅延ロードの場合、エンティティBeanに戻る前に関連付けられたクラスにアクセスすることによって関連付けられたクラスをロードする必要があります(次の例を参照).そうでない場合、クライアントが関連クラスにアクセスすると、ロード例外が放出されます.
public
Order getOrderByID(Integer orderid) {
Order order =
em
.find(Order.
class
, orderid);
//!!!!!
遅延ロードなので実行
size()
この方法で受注のすべての受注項目を取得します.
order.getOrderItems().size();
return
order;
}
また、遅延ロードの有無にかかわらずjoin fetch関連文により関連クラスを明示的にロードできます.
次の例を示します.
public
List getAllOrder() {
Query query =
em
.createQuery(
"select DISTINCT o from Order o inner
join fetch o.orderItems order by o.orderid"
);
List result = query.getResultList();
return
result;
}
変換元:
http://blog.csdn.net/gebitan505/article/details/22619175http://blog.csdn.net/lxl_family/article/details/26523757