双方向一対多(多対一)@OneToManyまたは@ManyToOneの使い方

9204 ワード

例えば、一例を用いて、JPAの一対多と多対一の学習を開始します.
  
例えば、ネットで本を買うと、ネットで注文します.
上記のビジネス・アクティビティの説明から、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