簡體   English   中英

多對多單向映射中的持久枚舉集

[英]Persisting set of Enums in a many-to-many unidirectional mapping

我使用帶有注釋的 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<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);

我想要發生的是在平台表中創建適當的行,即為 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

不知何故,當我嘗試持久化應用程序時,平台集沒有被持久化。 級聯注釋應該解決這個問題,但我不知道出了什么問題。

所以我的問題是:

  1. 有沒有更好的方法來模擬我想要做的事情,例如使用合適的枚舉?
  2. 如果我的模型沒問題,我如何正確地保留所有對象?

我已經為此苦苦掙扎了幾個小時,我已經嘗試重新創建上面的所有代碼,但它可能不完整和/或不准確。 我希望有人能指出一些顯而易見的事情!

您應該決定您的Platform是否是一個實體

如果是實體,則不能是enum ,因為可能平台的列表存儲在數據庫中,而不是應用程序中。 它應該是帶有@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沒有注釋。

在您的實體上簡單使用下面的映射。 假設我們有:

public enum TestEnum { A, B }

然后在您的實體類中:

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

下面的例子展示了當 Module 是一個實體而 Langue 是一個枚舉時的情況。

@Entity
public class Module {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  private String libelle;

  @ElementCollection(targetClass = Langue.class, fetch = FetchType.EAGER)
  @CollectionTable(name = "link_module_langue",
            joinColumns = @JoinColumn(name = "module_id", referencedColumnName = "id"))
  @Enumerated(EnumType.STRING)
  @Column(name = "langue")
  private Set<Langue> langues;
} 
public enum Langue {
  FRANCAIS, ANGLAIS, ESPAGNOLE
}

您應該創建link_module_langue表,請參閱以下 sql 代碼:

CREATE TABLE `link_module_langue` (
  `module_id` BIGINT(20) NOT NULL,
  `langue` VARCHAR(45) NOT NULL,
  PRIMARY KEY (`module_id`, `langue`),
  CONSTRAINT `module_fk`
    FOREIGN KEY (`module_id`)
    REFERENCES `module` (`id`)
    ON DELETE CASCADE
    ON UPDATE CASCADE);

注意:語言不是一個實體,不會有自己的表。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM