Я использую, в спящем режиме С 3.5.2 ФИНАЛОМ с аннотациями для определения моих отображений персистентности. Я борюсь с моделированием отношений между Приложением и рядом Платформ. Каждое приложение доступно для ряда платформ.
От всего чтения и поиска я сделал, я думаю, что у меня должен быть класс Enum платформы быть сохраненным как Объект и иметь объединяющую таблицу для представления many-many отношений. Я хочу, чтобы отношения были однонаправлены на уровне объектов, то есть, я хочу смочь получить список платформ для данного приложения, но я не должен узнавать список приложений для данной платформы.
Вот мои упрощенные образцовые классы:
@Entity
@Table(name = "TBL_PLATFORM")
public enum Platform {
Windows,
Mac,
Linux,
Other;
@Id
@GeneratedValue
@Column(name = "ID")
private Long id = null;
@Column(name = "NAME")
private String name;
private DevicePlatform() {
this.name = toString();
}
// Setters and getters for id and name...
}
@Entity
@Table(name = "TBL_APP")
public class Application extends AbstractEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Column(name = "NAME")
protected String _name;
@ManyToMany(cascade = javax.persistence.CascadeType.ALL)
@Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
@JoinTable(name = "TBL_APP_PLATFORM",
joinColumns = @JoinColumn(name = "APP_ID"),
inverseJoinColumns = @JoinColumn(name = "PLATFORM_ID"))
@ElementCollection(targetClass=Platform.class)
protected Set<Platform> _platforms;
// Setters and getters...
}
Когда я выполняю Быть в спящем режиме hbm2ddl инструмент, я вижу следующее (я использую MySQL):
create table TBL_APP_PLATFORM (
APP_ID bigint not null,
PLATFORM_ID bigint not null,
primary key (APP_ID, PLATFORM_ID)
);
Соответствующие внешние ключи также создаются от этой таблицы до таблицы приложения и таблицы платформы.Пока все хорошо.
Одна проблема, с которой я сталкиваюсь, состоит в том, когда я пытаюсь сохранить объект приложения:
Application newApp = new Application();
newApp.setName("The Test Application");
Set<DevicePlatform> platforms = EnumSet.of(Platform.Windows, Platform.Linux);
newApp.setPlatforms(platforms);
applicationDao.addApplication(newApp);
То, что я хотел бы произойти, для соответствующих строк в таблице Platform к созданному, т.е. создайте строку для Windows и Linux, если они уже не существуют. Затем строка для нового приложения должна быть создана, и затем отображение между новым приложением и этими двумя платформами в объединяющей таблице.
Одна проблема, с которой я сталкиваюсь, получает следующее исключение на этапе выполнения:
2010-06-30 13:18:09,382 6613126-0 ERROR FlushingEventListener Could not synchronize database state with session org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.example.model.Platform
Так или иначе набор платформы не сохраняется, когда я пытаюсь сохранить приложение. Каскадные аннотации, как предполагается, заботятся об этом, но я не знаю что случилось.
Таким образом, мои вопросы:
Я боролся с этим в течение многих часов, и я попытался воссоздать весь код выше, но это не могло бы быть завершено и/или точно. Я надеюсь, что кто-то укажет на что-то очевидное!
Вы должны решить, является ли ваша Платформа
сущностью или нет.
Если это сущность, это не может быть перечисление
, потому что список возможных платформ хранится в базе данных, а не в приложении. Это должен быть обычный класс с аннотацией @Entity
, и у вас будет нормальное отношение «многие ко многим».
Если это не объект, вам не нужна таблица TBL_PLATFORM
, и у вас нет отношения «многие ко многим». В этом случае вы можете представить набор Platform
либо как целочисленное поле с битовыми флагами, либо как простое отношение «один ко многим». JPA 2.0 упрощает последний случай с помощью @ElementCollection
:
@ElementCollection(targetClass = Platform.class)
@CollectionTable(name = "TBL_APP_PLATFORM",
joinColumns = @JoinColumn(name = "APP_ID"))
@Column(name = "PLATFORM_ID")
protected Set<Platform> _platforms;
-
create table TBL_APP_PLATFORM (
APP_ID bigint not null,
PLATFORM_ID bigint not null, -- the ordinal number of enum value
primary key (APP_ID, PLATFORM_ID)
);
и enum Platform
без аннотаций.