Java 多对多单向映射中的持久枚举集
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3152787/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Persisting set of Enums in a many-to-many unidirectional mapping
提问by gnuf
I'm using Hibernate 3.5.2-FINAL with annotations to specify my persistence mappings. I'm struggling with modelling a relationship between an Application and a set of Platforms. Each application is available for a set of platforms.
我使用带有注释的 Hibernate 3.5.2-FINAL 来指定我的持久性映射。我正在努力为应用程序和一组平台之间的关系建模。每个应用程序都可用于一组平台。
From all the reading and searching I've done, I think I need to have the platform enum class be persisted as an Entity, and to have a join table to represent the many-to-many relationship. I want the relationship to be unidirectional at the object level, that is, I want to be able to get the list of platforms for a given application, but I don't need to find out the list of applications for a given platform.
从我所做的所有阅读和搜索中,我认为我需要将平台枚举类作为实体持久化,并有一个连接表来表示多对多关系。我希望关系在对象级别是单向的,也就是说,我希望能够获取给定应用程序的平台列表,但我不需要找出给定平台的应用程序列表。
Here are my simplified model classes:
这是我的简化模型类:
@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...
}
When I run the Hibernate hbm2ddl tool, I see the following (I'm using MySQL):
当我运行 Hibernate hbm2ddl 工具时,我看到以下内容(我使用的是 MySQL):
create table TBL_APP_PLATFORM (
APP_ID bigint not null,
PLATFORM_ID bigint not null,
primary key (APP_ID, PLATFORM_ID)
);
The appropriate foreign keys are also created from this table to the application table and platform table. So far so good.
相应的外键也从该表创建到应用程序表和平台表。到现在为止还挺好。
One problem I'm running into is when I try to persist an application object:
我遇到的一个问题是当我尝试持久化一个应用程序对象时:
Application newApp = new Application();
newApp.setName("The Test Application");
Set<DevicePlatform> platforms = EnumSet.of(Platform.Windows, Platform.Linux);
newApp.setPlatforms(platforms);
applicationDao.addApplication(newApp);
What I would like to happen is for the appropriate rows in the Platform table to created, i.e. create a row for Windows and Linux, if they don't already exist. Then, a row for the new application should be created, and then the mapping between the new application and the two platforms in the join table.
我想要发生的是在平台表中创建适当的行,即为 Windows 和 Linux 创建一行,如果它们尚不存在。然后,应该为新应用程序创建一行,然后在连接表中新应用程序和两个平台之间的映射。
One issue I'm running into is getting the following runtime 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
Somehow, the platform set is not being persisted when I try to persist the application. The cascade annotations are supposed to take care of that, but I don't know what's wrong.
不知何故,当我尝试持久化应用程序时,平台集没有被持久化。级联注释应该解决这个问题,但我不知道出了什么问题。
So my questions are:
所以我的问题是:
- Is there a better way to model what I want to do, e.g. is using an Enum appropriate?
- If my model is alright, how do I properly persist all of the objects?
- 有没有更好的方法来模拟我想要做的事情,例如使用合适的枚举?
- 如果我的模型没问题,我如何正确地保留所有对象?
I've been struggling with this for hours, and I've tried to recreate all of the code above, but it might not be complete and/or accurate. I'm hoping someone will point out something obvious!
我已经为此苦苦挣扎了几个小时,我尝试重新创建上面的所有代码,但它可能不完整和/或不准确。我希望有人能指出一些显而易见的事情!
采纳答案by axtavt
You should decide whether your Platform
is an entityor not.
你应该决定你是否Platform
是一个实体。
If it's an entity, it can't be an enum
, because list of possible platforms is stored in the database, not in the application. It should be a regular class with @Entity
annotation and you will have a normal many-to-many relation.
如果是实体,则不能是enum
,因为可能平台的列表存储在数据库中,而不是应用程序中。它应该是带有@Entity
注释的常规类,并且您将拥有正常的多对多关系。
If it isn't an entity, then you don't need TBL_PLATFORM
table, and you don't have a many-to-many relation. In this case you can represent a set of Platform
s either as an integer field with bit flags, or as a simple one-to-many relation. JPA 2.0 makes the latter case simple with @ElementCollection
:
如果它不是实体,则不需要TBL_PLATFORM
表,也没有多对多关系。在这种情况下,您可以将一组Platform
s表示为带有位标志的整数字段,或者表示为简单的一对多关系。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)
);
and enum Platform
without annotations.
并且enum Platform
没有注释。
回答by Jayen Chondigara
Simple use below mapping on your entity. Suppose that we have:
在您的实体上简单使用下面的映射。假设我们有:
public enum TestEnum { A, B }
Then in your Entity class:
然后在您的实体类中:
@ElementCollection(targetClass = TestEnum.class)
@CollectionTable(
name = "yourJoinTable",
joinColumns = @JoinColumn(name = "YourEntityId")
)
@Column(name = "EnumId")
private final Set<TestEnum> enumSet= new HashSet<>();