2010-06-21 26 views
5

在我的域模型我有產品列表實體,具有以下Hibernate映射的產品實體之間的雙向directionnel協會:如何在不加載所有數據庫的情況下在列表中添加產品?

@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>(); 

... 
} 

但是,當我嘗試將產品添加到一個持久productList的Hibernate的嘗試加載所有的產品在列表中!我有超過14000種產品在列表中!

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); 
} 

如何在不加載所有數據庫的情況下在列表中添加產品?

回答

3

我想這是在需要更新連接表時使用ManyToMany關係的缺點之一。

我會建議創建出連接表的實體,然後你就只需要創建的連接實體,並將其保存:

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

    @ManyToOne(...) 
    private ProductList productList; 

    ... 
} 

而且你仍然可以有一個短暫的getter比將返回產品列表:

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); 
    } 
    ... 
} 

同樣的事情,爲manytomany關係的另一方。

然後,您的保存操作只是創建一個ProductListItem並保存它,它不會加載任何內容,只需要一個插入。

請注意您已經存在的hql查詢:如果他們使用鏈接Product < - > ProductList,他們將不再工作。

如果你想保持多對多關係,你應該看看:http://josephmarques.wordpress.com/2010/02/22/many-to-many-revisited/(我從來沒有嘗試這種解決方案)

+0

感謝您的文章!爲列表和產品之間的關係添加一個實體是解決插入問題的一個非常好的主意。但我的目標是創建一個有序的(@IndexColumn)產品列表。你知道如何管理新實體中的物品索引嗎? – 2010-06-24 09:28:26

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(); 

} 

} 
相關問題