2012-03-05 6 views
5

Durante la creazione di un'applicazione di negozio online utilizzando play-1.2.4, ho riscontrato alcuni problemi con jpa..Io volevo fornire un'area di amministrazione utilizzando lo CRUD module in riproduzione. Qui, un utente amministratore può creare/modificare o eliminare le entità nell'applicazione (come s, Order s, Item s ecc.).Eliminazione a catena in file di riproduzione: come modellare le entità

Un Customer può creare Orders.Each Order avrà una serie di CartItem s.When un Order viene eliminato, i corrispondenti CartItem s devono essere deleted.When un Customer viene eliminato, tutti i suoi ordini devono essere eliminati come well.I ho pensato di ottenere questo impostando la proprietà cascade nell'annotazione jpa.

ho modellato come questo

Customer.java

@Entity 
public class Customer extends Model { 
    @Email 
    @Required 
    public String email; 
    ... 
    @OneToMany(mappedBy="customer", cascade=CascadeType.ALL) 
    public List<Order> orders; 
    @OneToOne 
    public PayMethod currentPayment; 
    ... 
} 

Order.java

@Entity 
public class Order extends Model { 
    @OneToMany(cascade=CascadeType.ALL,orphanRemoval=true,fetch=FetchType.EAGER) 
    public Set<CartItem> cartItems; 

    @ManyToOne 
    public Customer customer; 
    @ManyToOne 
    public PayMethod paymentMethod; 
    ... 
} 

CartItem.java

@Entity 
public class CartItem extends Model implements Comparable<CartItem>{  
    @ManyToOne 
    public Item item; 
    public int quantity; 
} 

PayMethod.java

@Entity 
public class PayMethod extends Model { 
    @Required 
    public String cardNumber; 
    @ManyToOne 
    public Customer customer; 
    ... 
} 

Le seguenti tabelle di database sono stati creati

tabella dei clienti

id | email  | fullname | currentpayment_id 
---|-------------|---------------|----------------- 
2 |[email protected]| jon   |29 

tabella ordine

id |customer_id | paymentmethod_id 
----+------------+----------------- 
25 | 2   |  29 

tabella cartitem

id | quantity | item_id 
----+----------+--------- 
26 |  1 |  14 

* tabella order_cartitem *

01.235.164,106 mila
order_id | cartitems_id 
----------+-------------- 
     25 |   26 

nella interfaccia di amministrazione creati utilizzando CRUD (non ho implented alcun metodo, semplicemente utilizzando il modulo CRUD fornito come è), ho cercato di eliminare un cliente, ma poi, ottengo questo errore,

ERROR: update or delete on table "cartitem" violates foreign key constraint "fk7ff437ad3e28aa91" on table "order_cartitem" 
Detail: Key (id)=(26) is still referenced from table "order_cartitem". 
08:03:03,031 ERROR ~ Could not synchronize database state with session 

C'è qualcosa di sbagliato nel modo in cui ho modellato le Entità? Ho pensato che l'eliminazione sullo Customer sarà concatenata a Order e che a sua volta si sovrapporrà ai suoi CartItem s.

Cosa devo fare per ottenere questo effetto a cascata? O devo rimuovere manualmente ogni istanza contenuta di CartItem s?

EDIT: Come per la risposta di Seb

class Order extends Model { 
    @OneToMany(mappedBy="order", cascade=CascadeType.ALL,orphanRemoval=true,fetch=FetchType.EAGER) 
    public Set<CartItem> cartItems; 
    ... 
} 

class CartItem extends Model implements Comparable<CartItem>{ 

    @ManyToOne 
    public Item item; 

    public int quantity; 

    @ManyToOne 
    public Order order; 
... 
} 

static void addItemToCart(Long itemId,Long orderId,String quantity) { 
    Item item = Item.findById(itemId); 
    Order order = Order.findById(orderId); 
    int qty = Integer.parseInt(quantity); 
    CartItem cartItem = new CartItem(item,qty); 
    cartItem.order=order; 
    order.addItem(cartItem, qty); 
    order.save(); 
... 
} 

Questo elimina order_cartitem tavolo e aggiunge un campo order_id al tavolo cartitem

tavolo cartitem

 id | quantity | item_id | order_id 
    ----+----------+---------+---------- 
    26 |  1 |  14 |  25  
    27 |  1 |  20 |  25 

L'interfaccia admin(CRUD), elenca i Customer s e Order s.When un particolare Customer (colui che ha creato il Order) è selezionato e il tasto di cancellazione viene cliccato, si traduce in un JPA error

JPA error 
A JPA error occurred (Cannot commit): collection owner not associated with session: models.Order.cartItems 

qui è il stacktrace

Se qualcuno può capire perché questo sta accadendo, per favore dimmi.

È interessante notare che, posso cliccare sul delete button per un particolare Order, e chiama con successo il seguente metodo di controllo,

Admin.java

public static void deleteOrder(Long id) { 
    Order order = Order.findById(id); 
    order.delete();  
    ... 
} 

che elimina la Order e tutti il suo CartItem s ha avuto successo .. Quindi, perché questo non accade quando uno Customer viene cancellato?

+1

Il codice mi sembra a posto. Forse questo thread aiuta un po 'a trovare la causa del problema: http://stackoverflow.com/questions/2011519/jpa-onetomany-not-deleting-child – Bjarne77

+0

grazie per l'ottimo link..si passerà attraverso di esso –

risposta

2

Fai la tua bidirectionnal relazione con l'aggiunta di questo alla classe cartitem

@ManyToOne 
public Order order; 

e mappedBy = "ordine" nelle cartItems @OneToMany

poi Hibernate meglio gestisce la vostra eliminazione. Sto indovinando che senza questo collegamento bidirezionale, l'ibernazione ha provato a impostare prima la colonna su null. Puoi anche provare a consentire valori nulli nella tabella di join per vedere cosa succede se non vuoi abilitare la relazione bidirezionale

+0

grazie per la risposta ... ho provato questo, ora, quando ho provato a rimuovere un cliente tramite CRUD (Admin), ho ricevuto questo errore: ERROR ~ si è verificato un errore di asserzione (questo potrebbe indicare un bug in Hibernate, ma è più probabile a causa di insicurezze uso della sessione) org.hibernate.AssertionFailure: proprietario della raccolta non associato alla sessione: models.Order.cartItems –

+0

qui è [stacktrace] [1] [1]: http: //pastebin.com/r42mPEdB –

+0

Ho aggiornato il codice in questione (verso la fine) –

0

C'è un problema con le proprietà a cascata di JPA. Prova ad utilizzare le annotazioni a cascata correlate dalla sospensione e rimuovi tutte le cascate che hai utilizzato da JPA. Ecco un esempio per la classe del modello PayMethod:

// Be careful, import the realted annotations from hibernate (not JPA) 
import org.hibernate.annotations.OnDelete; 
import org.hibernate.annotations.OnDeleteAction; 

@Entity 
public class PayMethod extends Model { 
    @Required 
    public String cardNumber; 

    @ManyToOne 
    @OnDelete(action = OnDeleteAction.CASCADE) 
    public Customer customer; 
    ... 
} 

Sopra metodo funziona per me con la mappatura unidirezionale. Spero che questo risolva il tuo problema.

0

Ho avuto un problema simile, ma non stavo usando un elenco, stavo usando un array di entità.

Il problema con l'entità wrapping era che non inizializzava l'array (new MyEntity [0]) come faccio di solito con le mie liste (nuovo ArrayList (0)).

Mi sono reso conto (metodo empirico) che quando si prova a chiamare "unione" a una matrice "nullo" associata da una relazione "tutto-eliminazione-orfano", "org.hibernate.AssertionFailure: proprietario della raccolta non associato alla sessione :" sorsero.

Quindi il mio consiglio è: quando si utilizza una relazione "all-delete-orphans", inizializzare la raccolta (array incluso) con un'istanza vuota.

Problemi correlati