Multiple relationship with separate mapping table without generating foreign keys using Hibernate
I have two base abstract classes and of them some additional classes added, additional attributes added, etc.
There is a relationship between these specific derived types.
Simple illustrative example:
Role
and Group
classes abstract
, but they are not marked as @MappedSuperclass
.
InheritanceType.JOINED
the strategy is used, so both tables Role
(for the abstract class) and AdminRole
(for the derived class) must exist (both will have the same RoleID
).
-
DiscussionGroup
has one propertyAdminRole
, aSet<DiscussantRole>
, aSet<ManagerRole>
-
WorkingGroup
hasSet<WorkerRole>
,Set<ManagerRole>
Role
|-- AdminRole
|-- DiscussantRole
|-- ManagerRole
|-- WorkerRole
Group
|-- DiscussionGroup
|-- WorkingGroup
Since the number of derived classes can grow, and since classes derived from Roles can have relationships to different classes derived from a group (and vice versa), this will result in many different mapping tables (Worker_DiscussionGroup, Worker_WorkingGroup) or multiple foreign key columns (in M: 1 relationships - for example, the Role manager must have a DiscussionGroupID and a WorkingGroupId). I want to map all these relationships through one common mapping table.
Role_Group (RoleID, GroupId)
We use Hibernate to create the DDL schema (hbm2ddl.auto = create) during current development (we will use static schema definition for later use). Hibernate automatically creates foreign keys for relationships, which is not bad for us.
If I instruct to use the same table mapping for joins (many-to-many, many-to-many, and one-to-one), it tries to create keys . And of course it is not possible to create a foreign key on RoleID
from Role_Group
to AdminRole
and DiscussantRole
at the same time, which is why I get an error.
Is there a way how to tell Hibernate
-
to create selected relationships without foreign keys
or
-
to define that the relationship should be based on abstract ancestors (i.e. discussion group and its set should appear as 1: N - group and set)?
source to share
The following works for me as an answer to question number 2:
@ForeignKey( name = "none" )
No foreign key is generated for the relationship.
@Cascade( value = { CascadeType.ALL } )
@OneToOne( fetch = FetchType.EAGER, orphanRemoval = true )
@JoinTable( name = "Role_Group",
inverseJoinColumns = { @JoinColumn( referencedColumnName = "rolleId", name = "RolleID" ) },
joinColumns = { @JoinColumn( referencedColumnName = "groupId", name = "GroupID" ) } )
@ForeignKey( name = "none" )
public AdminRole getAdmin()
Sources:
Based on the sources, this is an undocumented feature that was seen in the release notes:
Changes in version 2.1.9 (xx.x.xxxx)
------------------------------------
* TimesTenDialect now supported (look at TimesTenDialect for certain limitations)
* foreign-key="none" can be used to disable generation of a foreign key.
In xml config - you would use it like this
<many-to-one name="Hospital" column="hospitalId" property-ref="hospitalId" update="false" insert="false" foreign-key="none">
as stated in Let Hibernate Connect Your World! (see page sources - xml config is not visible on page)
Note:
However, this does not solve the whole problem. Hibernate cannot get correct data through this mapping table for getAdmin
and getManagers
, since it looks like Role_Group
it finds RoleIDs
for DiscussionGroup
GroupID
and has no idea if it is for AdminRole
or ManagerRole
and gives "No row with given id exists" error ".
Mapping like this works, however, when I use a table like this in a Group or DiscussionGroup like public Set<Role> getRoles()
Hibernate will load the derived classes ( AdminRole
, ManagerRole
) in Set successfully .
source to share
I think you should be storing multiple tables. It just displays the relationships that exist in your classes.
If you don't want that, you can define Set<Role>
within the abstract Group
and Set<Group>
within the abstract Role
. You would not have "subsets" in your subclasses; you simply populate the set from the abstract class with the appropriate elements of the correct type. The auto mapping will then give you one junction table as you want.
source to share