2010-06-21 9 views
5

En mi modelo de dominio que tienen una asociación bi-directionnel entre la entidad la lista de productos y la entidad del producto con la siguiente asignación de hibernación:¿Cómo agregar un producto en una lista sin cargar toda la base de datos?

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

... 
} 

Pero cuando traté de añadir un producto a un persistente Lista del producto Hibernate intentará cargar todo el producto en la lista antes! ¡Tengo más de 14 000 productos en una lista!

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ómo agregar un producto en una lista sin cargar toda la base de datos?

Respuesta

3

supongo que es uno de los inconvenientes de utilizar una relación ManyToMany cuando necesita actualizar la tabla de unión.

Yo aconsejaría la creación de una entidad fuera de la tabla de unión, y, después, sólo habría tenido que crear la entidad unirse y guardarlo:

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

    @ManyToOne(...) 
    private ProductList productList; 

    ... 
} 

Y todavía podría tener un captador transitoria de lo que sería devolver una lista de productos de un producto:

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

Lo mismo para el otro lado de la relación manytomany.

Luego, su operación de salvar es simplemente una cuestión de crear un ProductListItem y guardarlo, que no cargará nada, y solo necesitará una inserción.

Tenga cuidado con sus consultas hql ya existentes: si utilizaran el enlace Producto < -> ProductList, ya no funcionarán.

si desea mantener la relación ManyToMany, usted debe buscar en: http://josephmarques.wordpress.com/2010/02/22/many-to-many-revisited/ (nunca he probado esta solución)

+0

Gracias por tu mensaje! Agregar una entidad para la relación entre la lista y el producto es una muy buena idea que resuelve el problema de inserción. Pero mi objetivo es crear una lista de productos ordenada (@IndexColumn). ¿Sabía cómo administrar el índice del artículo en la nueva entidad? –

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

} 

} 
Cuestiones relacionadas