каскадное удаление в playframework - как моделировать сущности - PullRequest
5 голосов
/ 05 марта 2012

При создании приложения интернет-магазина с использованием play-1.2.4 я столкнулся с некоторыми проблемами с jpa..Я хотел предоставить область администрирования, используя CRUD module в игре. Вот, администратор может создавать / редактировать или удалять объекты в приложении (например, Customer s, Order s, Item s и т. д.).

A Customer может создавать заказы. Каждый Order будет иметь набор CartItem s. Когда Order удаляется, соответствующие CartItem s должны быть удалены. Когда Customer удаляется все его приказы также должны быть удалены. Я думал, что смогу получить это, установив свойство cascade в аннотации jpa.

Я смоделировал это так

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

Были созданы следующие таблицы базы данных

таблица клиентов

id |  email      |   fullname    | currentpayment_id
---|-------------|---------------|-----------------
2  |jon@gmail.com| jon           |29 

стол заказов

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

таблица товаров

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

* стол заказа_карты *

 order_id | cartitems_id 
----------+--------------
       25 |           26

В интерфейсе администратора, созданном с использованием CRUD (я не внедрил никаких методов, просто использовал предоставленный модуль CRUD как есть), я попытался удалить клиента, но затем я получил эту ошибку,

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

Что-то не так с тем, как я моделировал сущности? Я думал, что удаление на Customer будет каскадно к Order, и это в свою очередь будет каскадно к CartItem с.

Что мне нужно сделать, чтобы получить этот каскадный эффект? Или я должен вручную удалить все содержащиеся в нем экземпляры CartItem s?

РЕДАКТИРОВАТЬ: Согласно ответу Себа

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

Это избавляет от order_cartitem таблицы и добавляет поле order_id к cartitem table

стол с корзиной

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

Интерфейс admin(CRUD), перечисляет Customer s и Order s. Когда выбран конкретный Customer (тот, кто создал Order) и нажата кнопка удаления, это приводит к JPA error

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

вот * трассировка стека

Если кто-то может понять, почему это происходит, пожалуйста, скажите мне.

Интересно, что я могу нажать delete button для определенного Order, и он успешно вызывает следующий метод контроллера,

Admin.java

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

, который удаляет Order и все его CartItem успешно .. Итак, почему этого не происходит при удалении Customer?

Ответы [ 3 ]

2 голосов
/ 05 марта 2012

Сделайте ваше отношение двунаправленным, добавив его в свой класс cartitem

@ManyToOne
public Order order;

и mappedBy = "order" в вашей корзине элементов @ OneToMany

тогда hibernate лучше обработает ваше удаление. Я предполагаю, что без этой двунаправленной ссылки hibernate попытался сначала установить для столбца значение null. Вы также можете попытаться разрешить нулевые значения в таблице соединений, чтобы увидеть, что произойдет, если вы не хотите включать двунаправленное отношение

0 голосов
/ 10 декабря 2012

У меня была похожая проблема, но я не использовал List, я использовал массив сущностей.

Проблема с моим обертывающим объектом заключалась в том, что он не инициализировал массив (new MyEntity [0]) как я обычно делаю со своими списками (новый ArrayList (0)).

Я понял (эмпирический метод), что при попытке вызвать «слияние» с массивом «ноль», связанным с «все-удалить»отношения "org.hibernate.AssertionFailure: владелец коллекции, не связанный с сеансом:" возникли.

Поэтому мой совет: при использовании отношения "all-delete-orphans" инициализируйтеколлекция (включая массив) с пустым экземпляром.

0 голосов
/ 06 марта 2012

Существует проблема с каскадными свойствами JPA.Попробуйте использовать связанные каскадные аннотации из спящего режима и удалите все каскады, которые вы использовали из JPA.Вот пример для вашего класса модели 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;
    ...
}

Приведенный выше метод работает для меня с однонаправленным отображением.Я надеюсь, что это решит вашу проблему.

...