2010-06-21 51 views
5

Trong mô hình tên miền của tôi Tôi có một hiệp hội bi-directionnel giữa thực thể ProductList và đơn vị sản phẩm với các bản đồ ngủ đông sau:Cách thêm sản phẩm vào danh sách mà không tải tất cả cơ sở dữ liệu?

@Entity @Indexed 
@Table(name="product_list") 
public class ProductList { 

@ManyToMany(fetch=FetchType.LAZY) 
@JoinTable(name = "list_items", 
     inverseJoinColumns = { @JoinColumn(name = "product_id")}, 
     joinColumns = { @JoinColumn(name = "list_id")}) 
@IndexColumn(name = "item_index", base = 1, nullable = false) 
@LazyCollection(LazyCollectionOption.EXTRA) 
@BatchSize(size=50) 
private List<Product> products = new LinkedList<Product>(); 
.... 

} 

@Entity 
@Table(name="logical_item") 
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE) 
public class Product { 

@ManyToMany(fetch=FetchType.LAZY, mappedBy="products") 
private Set<ProductList> productLists = new LinkedHashSet<ProductList>(); 

... 
} 

Nhưng khi tôi cố gắng thêm một sản phẩm cho một dai dẳng productList Hibernate cố gắng tải tất cả các sản phẩm trong danh sách trước đây! Tôi có hơn 14 000 sản phẩm trong một danh sách!

Product item = (Product) session.get(Product.class, 123); 
ProductList myFavoriteItems = (ProductList) session.get(ProductList.class, 321); 

// Evil lazy loading (need more 512Mo of memory) 
myFavoriteItems.addItem(Product item); 

public void addItem(Product item){ 
    this.getProducts().add(item); 
    item.getProductLists().add(this); 
} 

Cách thêm sản phẩm vào danh sách mà không tải tất cả cơ sở dữ liệu?

Trả lời

3

tôi đoán rằng đó là một trong những hạn chế của việc sử dụng mối quan hệ ManyToMany khi bạn cần cập nhật bảng tham gia.

tôi sẽ tư vấn cho việc tạo ra một thực thể ra khỏi bảng tham gia, và sau đó bạn sẽ chỉ phải tạo tham gia tổ chức và lưu nó:

public class ProductListItem { 
    @ManyToOne(...) 
    private Product product; 

    @ManyToOne(...) 
    private ProductList productList; 

    ... 
} 

Và bạn vẫn có thể có một getter thoáng hơn sẽ trả về một danh sách sản phẩm từ một sản phẩm:

public class Product { 

    @OneToMany(...) 
    private Set<ProductListItem> items; 

    @Transient 
    public Set<ProductList> getProductLists() { 
     Set<ProductList> list = new LinkedHashSet<ProductList>(); 
     for(ProductListItem item : items) { 
      list.add(item.getProductList()); 
     } 
     return Collections.unmodifiableSet(list); 
    } 
    ... 
} 

Điều tương tự cho phía bên kia của mối quan hệ nhiều năm.

Sau đó, thao tác lưu của bạn chỉ là vấn đề tạo một ProductListItem và lưu nó, sẽ không tải gì cả và chỉ cần một lần chèn.

Hãy cẩn thận với các truy vấn hql đã tồn tại của bạn: nếu chúng sử dụng liên kết Product < -> ProductList, chúng sẽ không hoạt động nữa.

nếu bạn muốn giữ mối quan hệ ManyToMany, bạn nên xem xét: http://josephmarques.wordpress.com/2010/02/22/many-to-many-revisited/ (i chưa bao giờ thử giải pháp này)

+0

Cám ơn bài viết của bạn! Thêm một thực thể cho mối quan hệ giữa danh sách và sản phẩm là một ý tưởng rất tốt giải quyết vấn đề chèn. Nhưng mục tiêu của tôi là tạo ra một danh sách các sản phẩm (@IndexColumn) có thứ tự. Bạn có biết cách quản lý chỉ mục mục trong thực thể mới không? –

0
public class Controller { 

private static SessionFactory sf = HibernateUtil.getSessionFactory(); 

/** 
* @param args 
*/ 
public static void main(String[] args) { 
// construct data 
sf.getCurrentSession().beginTransaction(); 
Item i1 = new Item("i1"); 
Item i2 = new Item("i2"); 
Item i3 = new Item("i3"); 
Category c1 = new Category("c1"); 
sf.getCurrentSession().save(i1); 
sf.getCurrentSession().save(i2); 
sf.getCurrentSession().save(i3); 
sf.getCurrentSession().save(c1); 
c1.getItems().add(i1); 
i1.getCategories().add(c1); 
c1.getItems().add(i2); 
i2.getCategories().add(c1); 
sf.getCurrentSession().getTransaction().commit(); 

// get Category & i (i3) 
sf.getCurrentSession().beginTransaction(); 
Category c = (Category) sf.getCurrentSession().get(Category.class, c1.getId()); 
Item i = (Item) sf.getCurrentSession().get(Item.class, i3.getId()); 

// proxys i & c have null Set 
System.out.println("i : " + i.getName()); 
System.out.println("c : " + c.getName()); 

// here we have the IDs 
long category_id = c.getId(); 
long item_id = i.getId(); 

sf.getCurrentSession().getTransaction().commit(); 

// add many to many data 
sf.getCurrentSession().beginTransaction(); 

// here we can use pure SQL to add a line in CATEGORY_ITEM. 
// with the known IDs 
String ins = "insert into category_items (item_id,category_id,item_index) SELECT 4639, 100, MAX(item_index)+1 from category_items where category_id = 100 ;"; 

sf.getCurrentSession().getTransaction().commit(); 

} 

} 
Các vấn đề liên quan