在多对多单向映射中保留枚举集

我正在使用带有注释的Hibernate 3.5.2-FINAL来指定我的持久性映射。 我正在努力建模应用程序和一组平台之间的关系。 每个应用程序都可用于一组平台。

从我所做的所有阅读和搜索中,我认为我需要将平台枚举类保持为实体,并使用连接表来表示多对多关系。 我希望关系在对象级别是单向的,也就是说,我希望能够获得给定应用程序的平台列表,但我不需要找出给定平台的应用程序列表。

这是我的简化模型类:

@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 _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 platforms = EnumSet.of(Platform.Windows, Platform.Linux); newApp.setPlatforms(platforms); applicationDao.addApplication(newApp); 

我想要发生的是创建Platform表中的相应行,即为Windows和Linux创建一行(如果它们尚不存在)。 然后,应创建新应用程序的行,然后创建新应用程序与连接表中的两个平台之间的映射。

我遇到的一个问题是获得以下运行时exception:

 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 

不知何故,当我尝试持久化应用程序时,平台集不会被持久化。 级联注释应该照顾它,但我不知道什么是错的。

所以我的问题是:

  1. 有没有更好的方法来模拟我想要做的事情,例如使用适当的Enum?
  2. 如果我的模型没问题,我该如何正确地保留所有对象?

我一直在努力解决这个问题几个小时,我试图重新创建上面的所有代码,但它可能不完整和/或准确。 我希望有人会指出一些明显的东西!

您应该决定您的Platform是否是实体

如果它是一个实体,则它不能是enum ,因为可能的平台列表存储在数据库中,而不是存储在应用程序中。 它应该是具有@Entity注释的常规类,并且您将具有正常的多对多关系。

如果它不是实体,那么您不需要TBL_PLATFORM表,并且您没有多对多关系。 在这种情况下,您可以将一组Platform表示为带有位标志的整数字段,或者表示为简单的一对多关系。 使用@ @ElementCollection JPA 2.0使后一种情况变得简单:

 @ElementCollection(targetClass = Platform.class) @CollectionTable(name = "TBL_APP_PLATFORM", joinColumns = @JoinColumn(name = "APP_ID")) @Column(name = "PLATFORM_ID") protected Set _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

在您的实体下面的映射下使用简单。 假设我们有:

 public enum TestEnum { A, B } 

然后在你的Entity类中:

 @ElementCollection(targetClass = TestEnum.class) @CollectionTable( name = "yourJoinTable", joinColumns = @JoinColumn(name = "YourEntityId") ) @Column(name = "EnumId") private final Set enumSet= new HashSet();