How to express polymorphic association in JPA?

A polymorphic association is similar to a foreign key or many-to-one relationship, with the difference that the target can be one of several types (classes in the language, tables in db).

I am transferring a database design that I have been using for several years from PHP to Java. In the old code, I deployed my own ORM, which was not optimal for a number of reasons. Although I could start customizing things later and maybe re-implement my things, while I would like to use ready-made ORM and JPA for my entity classes.

Now, one thing about the database layout that I donโ€™t know how to express in JPA:

I have a Node and Edge table that stores the graph (DAG, if that matters). Each node may optionally refer to a different object from the database. These entites can be negotiated several times throughout the schedule, and there can also be โ€œorphanedโ€ entites that will not be available to the user, but which may make sense at least for some time.

These objects are not related at all in terms of inheritance, etc., but have a natural hierarchy similar to Customer-> Site-> Floor-> Room. In fact, many years ago, I started with only the foreign key fields pointing to the "parent" objects. However, this hierarchy is not flexible enough and began to fall apart.

For example, I want to allow users to group objects in folders, some objects may have several "parents", as well as changes over time. I need to keep track of how the relationship was, so the edegs chart has a time slot associated with them that indicates when and when this edge was valid.

The link from the node to the object is stored in two columns of the node table, one contains the identifier in the external table, one has its own name. For example (some columns are omitted):

 table Node: +--------+-------+----------+ | ixNode | ixRef | sRefType | +--------+-------+----------+ | 1 | NULL | NULL | <-- this is what a "folder" would look like | 2 | 17 | Source | | 3 | 58 | Series | <-- there seven types of related objects so far +--------+-------+----------+ table Source (excerpt): +----------+--------------------+ | ixSource | sName | +----------+--------------------+ | 16 | 4th floor breaker | | 17 | 5th floor breaker | | 18 | 6th floor breaker | +----------+--------------------+ 

There may be a different solution than using JPA. I could change something in the layout of the table or introduce a new table, etc. However, I already thought a lot about this, and it seems to me that the table structure suits me. Perhaps there is a third way that I did not think about.

+4
source share
4 answers

I think you already answered. Create an abstract class (either @Entity or @MappedSuperclass) and its various types extend.

Something like this might work

 @MappedSuperclass @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) public abstract class Edge { // . . . @OneToMany Collection<Node> nodes; } @Entity public class Source extends Edge { } @Entity public class Series extends Edge { } @Entity public class Node { // . . . @ManyToOne Edge edge; } 

I understand that you may not want to imply a relationship between the Source and the Series, but extending the general abstract (without table) class is the only way I can think about what needs to be done.

InheritanceType.TABLE_PER_CLASS will keep Source and Series in separate tables (you can use SINGLE_TABLE to do something like the previous answer).

If this is not what you are looking for, many JPA providers provide a tool that creates mappings based on an existing set of tables. In OpenJPA, it is called ReverseMappingTool [1]. The tool will generate Java source files that you can use as a starting point for your mappings. I suspect that Hibernate or EclipseLink have something similar, but you can just use OpenJPA alone and use entity definitions with another provider (the tool does not generate any OpenJPA code, as far as I know).

[1] http://openjpa.apache.org/builds/latest/docs/manual/manual.html#ref_guide_pc_reverse

+5
source

The answer will be as follows:

  • inheritance (as suggested by Mike)
  • plus @DiscriminatorColumn to provide information whose column stores information about which subclass should be used: sxRef. The only doubt I see is "sxRef", which is a column with zero . I guess this is forbidden.
+5
source

Have you viewed the @Any annotation? This is not part of the JPA, but an extension of the Hibernate Annotation extension.

+2
source

How much information is stored in the source and series tables? Is that just a name? If so, you can combine them into one table and add a column of "type". Your Node table will lose its sRefType, and you will have a new table that looks like this:

 ixSource sName sType 16 4th floor breaker SOURCE 17 5th floor breaker SOURCE 18 6th floor breaker SOURCE 19 1st floor widget SERIES 20 2nd floor widget SERIES 

This table will replace the Source and Series tables. Is there a source and series belonging to the superclass? This will be the natural name for this table.

0
source

All Articles