I would like to have a JoinTable between 2 entities, this two entities are derived from the same owner entity. So when joining this entities using @ManyToMany relationship I have got @JoinTable (like in below DDL):
CREATE TABLE IF NOT EXISTS `local_services`.`service_provided_on` (
`provider_id` INT UNSIGNED NOT NULL,
`service_id` INT UNSIGNED NOT NULL,
`service_point_no` INT UNSIGNED NOT NULL,
`work_station_no` INT UNSIGNED NOT NULL,
PRIMARY KEY (`provider_id`, `service_id`, `service_point_no`, `work_station_no`),
INDEX `fk_provider_service_has_work_station_work_station1_idx` (`service_point_no` ASC, `work_station_no` ASC, `provider_id` ASC),
INDEX `fk_provider_service_has_work_station_provider_service1_idx` (`provider_id` ASC, `service_id` ASC),
CONSTRAINT `fk_service_provided_on_provider_service`
FOREIGN KEY (`provider_id` , `service_id`)
REFERENCES `local_services`.`provider_service` (`provider_id` , `service_id`)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT `fk_service_provided_work_station`
FOREIGN KEY (`service_point_no` , `work_station_no` , `provider_id`)
REFERENCES `local_services`.`work_station` (`service_point_no` , `work_station_no` , `provider_id`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB
As you can see there are 2 Foreign Keys and each of them is using the same provider_id column. I would like to define using this @JoinTable, Services provided by given Provider on belonging to it WorkPlace (WorkStation). It will be obvious that service provided by provider with id ex. 5 can be only provided on workplace belonging to provider with id 5. So the best will be to share this @JoinColumn between each ForeignKeys. And when trying for example inserting workplace/service with not matching provider id to raise some exception!
I try to do something like this:
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "service_provided_on",
joinColumns = {
@JoinColumn(name = "provider_id", referencedColumnName = "provider_id", nullable = false, columnDefinition = "BIGINT UNSIGNED"),
@JoinColumn(name = "service_id", referencedColumnName = "service_id", nullable = false, columnDefinition = "INT UNSIGNED")
},
inverseJoinColumns = {
@JoinColumn(name = "provider_id", referencedColumnName = "provider_id", insertable = false, updatable = false),
@JoinColumn(name = "service_point_no", referencedColumnName = "service_point_no", nullable = false, columnDefinition = "INT UNSIGNED"),
@JoinColumn(name = "work_station_no", referencedColumnName = "work_station_no", nullable = false, columnDefinition = "INT UNSIGNED")
}
)
But it obviously doesn't work and raise exception like this:
Caused by: org.hibernate.MappingException: Repeated column in mapping for collection: pl.salonea.entities.WorkStation.providedServices column: provider_id"}}
I consider renaming for one foreign key this provider_id ex. work_station_provider_id but then I will be allowed to insert not matching provider_ids and maybe I could define some CONSTRAINT to block such behaviour (how to define this in JPA?). It can work but I will have redundant column with the same provider_id
In some ways, mapping your model this way does not quite make sense. There is nothing in your many-to-many relationship that guarantees that the
Service
s andLocation
s in the relationship must have the sameProvider
. I would change your object model to make that requirement explicit. Add a one-to-many relationship betweenProvider
and a new objectServiceProvidedOn
(not the greatest name; maybe something likeServiceOccurrence
?). SoProvider
would have a collection attributeserviceProvidedOns
; and the new classServiceProvidedOn
would have three attributesprovider
,service
, andworkStation
(mapped appropriately). The primary key forServiceProvidedOn
would be derived from the three other objects (Provider
,Service
, andWorkStation
).[I have made a number of assumptions about your model; so I hope this suggestion makes sense.]