JPA ManyTomany Reference Issue
Pergunta
Eu tenho três mesas. Disponível OPTions e Plantyperef com uma tabela de associações ManyTomany chamada uptionPlantyPeasSoc. Os esquemas aparados são assim
CREATE TABLE [dbo].[AvailableOptions](
[SourceApplication] [char](8) NOT NULL,
[OptionId] [int] IDENTITY(1,1) NOT NULL,
...
)
CREATE TABLE [dbo].[AvailOptionPlanTypeAssoc](
[SourceApplication] [char](8) NOT NULL,
[OptionId] [int] NOT NULL,
[PlanTypeCd] [char](2) NOT NULL,
)
CREATE TABLE [dbo].[PlanTypeRef](
[PlanTypeCd] [char](2) NOT NULL,
[PlanTypeDesc] [varchar](32) NOT NULL,
)
E o código Java se parece com isso.
//AvailableOption.java
@ManyToMany(cascade={CascadeType.ALL}, fetch=FetchType.EAGER)
@JoinTable(
name = "AvailOptionPlanTypeAssoc",
joinColumns = { @JoinColumn(name = "OptionId"),
@JoinColumn(name="SourceApplication")},
inverseJoinColumns=@JoinColumn(name="PlanTypeCd"))
List<PlanType> planTypes = new ArrayList<PlanType>();
//PlanType.java
@ManyToMany
@JoinTable(
name = "AvailOptionPlanTypeAssoc",
joinColumns = { @JoinColumn(name = "PlanTypeCd")},
inverseJoinColumns={@JoinColumn(name="OptionId"),
@JoinColumn(name="SourceApplication")})
List<AvailableOption> options = new ArrayList<AvailableOption>();
O problema surge ao fazer uma seleção nas opções disponíveis que se une a si mesma. Observe o seguinte código SQL do backtrace. A segunda junção interna deve estar no Plantyperef.
SELECT t0.OptionId,
t0.SourceApplication,
t2.PlanTypeCd,
t2.EffectiveDate,
t2.PlanTypeDesc,
t2.SysLstTrxDtm,
t2.SysLstUpdtUserId,
t2.TermDate
FROM dbo.AvailableOptions t0
INNER JOIN dbo.AvailOptionPlanTypeAssoc t1
ON t0.OptionId = t1.OptionId AND t0.SourceApplication = t1.SourceApplication
INNER JOIN dbo.AvailableOptions t2
ON t1.PlanTypeCd = t2.PlanTypeCd
WHERE (t0.SourceApplication = ? AND t0.OptionType = ?)
ORDER BY t0.OptionId ASC, t0.SourceApplication ASC
[params=(String) testApp, (String) junit0]}
Solução
Você está mapeando uma associação bidirecional. Isso significa que você precisa escolher um lado como proprietário da associação. Este lado será responsável por atualizar o relacionamento no banco de dados.
Se você escolher o DanualOption como proprietário do relacionamento e deseja um novo Plantype para ele, precisará adicionar o Plantype à opção. Adicionar a opção apenas ao Plantype não terá efeito.
Aqui está o mapeamento:
//AvailableOption.java
@ManyToMany(cascade={CascadeType.ALL}, fetch=FetchType.EAGER)
@JoinTable(
name = "AvailOptionPlanTypeAssoc",
joinColumns = { @JoinColumn(name = "OptionId"),
@JoinColumn(name="SourceApplication")},
inverseJoinColumns=@JoinColumn(name="PlanTypeCd"))
List<PlanType> planTypes = new ArrayList<PlanType>();
//PlanType.java
@ManyToMany(
mappedBy = "planTypes"
)
List<AvailableOption> options = new ArrayList<AvailableOption>();
Você também pode se referir ao Documentação da anotação de hibernação Capítulo 2.2.5
Atenciosamente David