【问题标题】:How to add a product in a list without loading all the database?如何在不加载所有数据库的情况下在列表中添加产品?
【发布时间】:2010-06-21 14:43:33
【问题描述】:

在我的域模型中,我在 ProductList 实体和 Product 实体之间有一个双向关联,具有以下休眠映射:

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

...
}

但是当我尝试将产品添加到持久产品列表中时,休眠尝试加载列表中的所有产品!我的列表中有超过 14 000 种产品!

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

如何在不加载所有数据库的情况下将产品添加到列表中?

【问题讨论】:

    标签: database hibernate many-to-many lazy-loading


    【解决方案1】:

    我想这是在需要更新连接表时使用多对多关系的缺点之一。

    我建议从连接表中创建一个实体,然后您只需创建连接实体并保存它:

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

    多对多关系的另一端也是如此。

    然后,您的保存操作只是创建一个 ProductListItem 并保存它,它不会加载任何内容,并且只需要一次插入。

    小心您已经存在的 hql 查询:如果他们使用链接 ProductProductList,他们将不再工作。

    如果您希望保持多对多关系,您应该查看:http://josephmarques.wordpress.com/2010/02/22/many-to-many-revisited/(我从未尝试过此解决方案)

    【讨论】:

    • 感谢您的帖子!为列表和产品之间的关系添加一个实体是解决插入问题的一个非常好的主意。但我的目标是创建一个有序的 (@IndexColumn) 产品列表。你知道如何管理新实体中的项目索引吗?
    【解决方案2】:
    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();
    
    }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-04-28
      • 2015-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多