2012-06-08 3 views
0

Я, хотя его простой, что я хочу, но я не могу найти решение для моей проблемы. Я использую playframework 1.2.3, и он использует Hibernate как JPA. Поэтому я думаю, что playframework не имеет ничего общего с проблемой.JPA сущность дизайн/не может удалить объект

У меня есть несколько классов (Я опускаю nonrelevant поля)

public class User { 
    ... 
} 

public class Task { 
    public DataContainer dataContainer; 
} 

public class DataContainer { 
    public Session session; 
    public User user; 
} 

public class Session { 
    ... 
} 

Так у меня есть связь от задачи к DataContainer и от DataContainer к Sesssion и DataContainer принадлежит пользователю. У DataContainers всегда может быть один и тот же пользователь, но для каждого экземпляра сеанс должен быть другим. И DataContainer задачи также должен быть разным в каждом случае. У DataContainer может быть Sesesion или нет (это optinal). Я использую только однонаправленный. Этого должно быть достаточно.

Другими словами: Каждая задача должна имеет один DataContainer. Каждый DataContainer должен имеет одного и того же пользователя и может иметь одну сессию.

Чтобы создать схему БД я использую JPA аннотации:

@Entity 
public class User extends Model { 
    ... 
} 

@Entity 
public class Task extends Model { 
    @OneToOne(optional = false, cascade = CascadeType.ALL) 
    public DataContainer dataContainer; 
} 

@Entity 
public class DataContainer extends Model { 
    @OneToOne(optional = true, cascade = CascadeType.ALL) 
    public Session session; 

    @ManyToOne(optional = false, cascade = CascadeType.ALL) 
    public User user; 
} 

@Entity 
public class Session extends Model { 
    ... 
} 

КСТАТИ: Модель представляет собой класс игры и обеспечивает основной идентификатор, пока тип.

Когда я создаю для каждой сущности какой-либо объект и «соединяю его», я имею в виду ассоциации, он отлично работает. Но когда я пытаюсь удалить сеанс, я получаю исключение нарушения ограничения, потому что DataContainer все еще ссылается на сеанс, который я хочу удалить.

Я хочу, чтобы сессия (поле) DataContainer была установлена ​​равной нулю, поэтому внешний ключ (session_id) должен быть удален в базе данных. Это будет хорошо, потому что это необязательно.

Я не знаю, я думаю, что у меня много проблем. Использую ли я правую аннотацию @OneToOne?

Я нашел в Интернете дополнительные аннотации и атрибуты: @JoinColumn и атрибут mappedBy для обратной связи. Но у меня его нет, потому что он не двунаправлен. Или является двунаправленным партнером. по существу?

Другая попытка была использовать @OnDelete(action = OnDeleteAction.CASCADE) contraint изменился с NO ACTION х годов, когда обновление или удаление в:

ADD CONSTRAINT fk4745c17e6a46a56 FOREIGN KEY (session_id) 
     REFERENCES annotation_session (id) MATCH SIMPLE 
     ON UPDATE NO ACTION ON DELETE CASCADE; 

Но в этом случае, когда я удалить сеанс, в DataContainer пользователя и удаляется. Это неправильно для меня.


EDIT: Я использую PostgreSQL 9, материал JDBC входит в игру, мой единственный дб конфигурации является
db=postgres://app:[email protected]:5432/app

+0

Может быть, это работает: добавить '@OneToOne DataContainer' в' Session' и изменить атрибут сеанса из DataContainer в '@OneToOne (mappedBy = "dataContainer") '. Таким образом, класс 'DataContainer' больше не нуждается в столбце' session_id'. –

ответ

3

Следует ли использовать OneToOne или ManyToOne? Используйте ассоциацию, которая лучше всего описывает ситуацию.Если несколько DataContainers могут иметь один и тот же сеанс, это ManyToOne. Если только один DataContainer может иметь данный сеанс, то это OneToOne.

Теперь, если вы удалите сеанс, и DataContainer все еще ссылается на него, вы получите исключение. Для этого нужны FK: он гарантирует, что у вас не будет DataContainer, который ссылается на не существующий сеанс. Итак, чтобы удалить сеанс, вы должны сначала обновить все контейнеры данных, ссылающиеся на него.

Поскольку ваша ассоциация является однонаправленной, вам нужен запрос, чтобы сделать это:

select dc from DataContainer dc where dc.session = :session 

Выполнить этот запрос, перебирать результаты, и установить сессию в нуль. Затем удалите сеанс.

Если ваша ассоциация была двунаправленной, вы можете просто сделать:

for DataContainer dc : session.getDataContainers() { 
    dc.setSession(null); 
} 

Можно также использовать запрос на обновление, чтобы сделать все в одном запросе. Но следует помнить, что эти изменения не будут внесены уже загружены DataContainers в сессии:

update DataContainer dc set dc.session = null where dc.session = :session 
+0

ну да, это на самом деле не очень сложно. Я мог решить его только с помощью JPA-аннотации. Я использую ваш первый вариант и устанавливаю нулевой сеанс в DataContainers перед удалением сеанса: я переопределяю метод _delete в контроллере сеанса и делаю это перед вызовом super._delete() Спасибо! – timaschew

0

не уверен, но что используется база данных? загружается ли спящий режим автоматически, или вы используете свой собственный DDL-запрос для его создания. если это так, пожалуйста, проверьте, установлено ли ограничение на уровне базы данных, убедитесь, что внешний ключ sessionId в таблице DataContainer является нулевым.

+0

жаль, что я забыл. Я использую postgresql 9 – timaschew

Смежные вопросы