2010-06-21 11 views
5

Nel mio modello di dominio Ho un associazione bi-directionnel tra l'entità ProductList e l'entità del prodotto con il seguente mapping Hibernate:Come aggiungere un prodotto in un elenco senza caricare tutto il database?

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

... 
} 

Ma quando ho cercato di aggiungere un prodotto ad un persistente ProductList Hibernate provare a caricare tutto il prodotto nella lista prima! Ho più di 14000 prodotti in 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); 
} 

Come aggiungere un prodotto in un elenco senza caricare tutto il database?

risposta

3

Immagino che sia uno degli svantaggi dell'utilizzo di una relazione ManyToMany quando è necessario aggiornare la tabella di join.

vorrei consigliare la creazione di un soggetto fuori dalla tabella di aderire, e poi si sarebbe avuto solo per creare l'entità unirsi e salvarlo:

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

    @ManyToOne(...) 
    private ProductList productList; 

    ... 
} 

e si potrebbe ancora avere un getter transitoria di quanto sarebbe restituire un lista prodotti da un prodotto:

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

Stessa cosa per l'altro lato della relazione molte.

Quindi, l'operazione di salvataggio è solo una questione di creazione di un oggetto ProductListItem e di salvataggio, che non caricherà nulla e richiede un solo inserto.

Prestare attenzione alle query hql già esistenti: se hanno utilizzato il collegamento Prodotto < -> Elenco prodotti, non funzioneranno più.

se si desidera mantenere la relazione ManyToMany, si dovrebbe guardare: http://josephmarques.wordpress.com/2010/02/22/many-to-many-revisited/ (non ho mai provato questa soluzione)

+0

Grazie per il tuo post! Aggiungi un'entità per la relazione tra l'elenco e il prodotto è una buona idea che risolve il problema dell'inserto. Ma il mio obiettivo è creare un elenco ordinato di prodotti (@IndexColumn). Sai come gestire l'indice degli oggetti nella nuova entità? –

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

} 

} 
Problemi correlati