我使用带有注释的Hibernate 3.5.2-FINAL来指定我的持久性映射。我正在努力对应用程序和一组平台之间的关系进行建模。每个应用程序都可用于一组平台。
从我完成的所有阅读和搜索中,我认为我需要让平台枚举类作为Entity持久化,并需要一个联接表来表示多对多关系。我希望该关系在对象级别是单向的,也就是说,我希望能够获得给定应用程序的平台列表,但是我不需要找出给定平台的应用程序列表。
这是我的简化模型类:
@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... }
当我运行Hibernate 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
以某种方式,当我尝试持久化应用程序时,平台集并没有被持久化。级联注释应该可以解决这个问题,但是我不知道这是怎么回事。
所以我的问题是:
我已经为此苦苦挣扎了几个小时,并且尝试重新创建上面的所有代码,但是它可能并不完整和/或准确。我希望有人指出一些明显的东西!
您应该确定您Platform是否为 实体 。
Platform
如果是实体,则不能是enum,因为可能平台的列表存储在数据库中,而不是应用程序中。它应该是带有@Entity注释的常规类,并且您将具有正常的多对多关系。
enum
@Entity
如果不是实体,则不需要TBL_PLATFORM表,也就没有多对多关系。在这种情况下,您可以将Platforms 的集合表示为带有位标志的整数字段,或者表示为简单的一对多关系。JPA 2.0使用@ElementCollection以下命令简化了后一种情况:
TBL_PLATFORM
@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没有注释。
enum Platform