在我的域模型中,我在ProductList实体和Product实体之间有一个双向关联,具有以下hibernate映射:
@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>();
...
}
但是当我尝试将产品添加到持久性产品列表时,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);
}
如何在列表中添加产品而不加载所有数据库?
答案 0 :(得分:3)
我想当你需要更新连接表时,使用ManyToMany关系是一个缺点。
我建议从连接表中创建一个实体,然后你只需要创建连接实体并保存它:
public class ProductListItem {
@ManyToOne(...)
private Product product;
@ManyToOne(...)
private ProductList productList;
...
}
你可能仍然有一个短暂的吸气剂,而不是从产品中返回产品清单:
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);
}
...
}
与许多关系的另一面相同。
然后,您的保存操作只是创建一个ProductListItem并保存它,它将不加载任何内容,只需要一个插入。
小心你已经存在的hql查询:如果他们使用了链接Product&lt; - &gt; ProductList,它们将不再起作用。
如果你想保持ManyToMany关系,你应该看看:http://josephmarques.wordpress.com/2010/02/22/many-to-many-revisited/(我从来没有尝试过这个解决方案)
答案 1 :(得分: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();
}
}