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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 16:53:59  来源:igfitidea点击:

Persisting set of Enums in a many-to-many unidirectional mapping

javahibernatejpapersistenceannotations

提问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:

所以我的问题是:

  1. Is there a better way to model what I want to do, e.g. is using an Enum appropriate?
  2. If my model is alright, how do I properly persist all of the objects?
  1. 有没有更好的方法来模拟我想要做的事情,例如使用合适的枚举?
  2. 如果我的模型没问题,我如何正确地保留所有对象?

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 Platformis 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 @Entityannotation and you will have a normal many-to-many relation.

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

If it isn't an entity, then you don't need TBL_PLATFORMtable, and you don't have a many-to-many relation. In this case you can represent a set of Platforms 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表,也没有多对多关系。在这种情况下,您可以将一组Platforms表示为带有位标志的整数字段,或者表示为简单的一对多关系。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 Platformwithout 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<>();