Permanent Enums in Multidimensional Unidirectional Matching

I use Hibernate 3.5.2-FINAL with annotations to indicate my persistence mappings. I struggle with modeling the relationship between the Application and the set of platforms. Each application is available for a set of platforms.

Of all the checks and searches I've done, I think I need the platform enumeration class to be saved as Entity, and have a join table to represent many-to-many relationships. I want the relationship to be unidirectional at the object level, that is, I would like to get a list of platforms for this application, but I do not need to look for a list of applications for this 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 use MySQL):

 create table TBL_APP_PLATFORM ( APP_ID bigint not null, PLATFORM_ID bigint not null, primary key (APP_ID, PLATFORM_ID) ); 

Corresponding foreign keys are also generated from this table to the application table and platform table. So far so good.

One problem that I am facing is when I try to save the 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); 

I would like the corresponding rows in the Platform table to be created, i.e. created a string for Windows and Linux if they do not already exist. Then a row should be created for the new application, and then a mapping between the new application and the two platforms in the connection table.

One issue that I am facing is the following exception to execute:

 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 

Be that as it may, the toolbox is not saved when I try to save the application. Cascading annotations should take care of this, but I don't know what happened.

So my questions are:

  • Is there a better way to simulate what I want to do, for example. Is Enum suitable?
  • If my model is fine, how do I save all objects correctly?

I struggled with this for several hours and I tried to recreate all the code above, but it may not be complete and / or accurate. I hope someone points out something obvious!

+17
java annotations hibernate jpa persistence
Jun 30 '10 at 19:37
source share
2 answers

You must decide whether your Platform entity or not.

If it is an object, it cannot be enum , because the list of possible platforms is stored in the database, and not in the application. This should be a regular class with @Entity annotation, and you will have a normal many-to-many relationship.

If this is not an entity, you do not need the TBL_PLATFORM table, and you do not have a many-to-many relationship. In this case, you can represent the Platform set as either a whole field with bit flags, or as a simple one-to-many relationship. JPA 2.0 makes the latter case simple with @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.

+33
Jun 30 '10 at 20:33
source share

Simple use below display on your object. Suppose 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<TestEnum >(); 
+2
Oct 23 '15 at 13:52
source share



All Articles