JPA @ManyToMany 只有部分主键
JPA @ManyToMany with only part of primary Key
我通过第三个 table:
在两个 table 之间建立了多对多关系
TABLE_A A_TO_B TABLE_B
--------- ------------- ------------
KEY (PK) KEY_A (PK, FK) KEY (PK)
--some more Atributes KEY_B (PK, FK) START_DATE (PK)
--some Attributes END_DATE
--some Attributes
如您所见,此 Table 结构的问题在于 Table B
具有包含条目开始日期的组合主键。这是为了能够有入门版。我无法更改 table 结构。我想通过 @ManyToMany
属性在 JPA 中加入 TABLE_A
和 TABLE_B
。但是 JPA 要求 A_TO_B
知道 TABLE_B
的完整主键。但是我会完全满足于忽略 START_DATE
并只获取 TABLE_B
和 KEY_B
的所有条目以获得特定的 KEY_A
。
这是错误:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [spring_hibernate_configuration.xml]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: referencedColumnNames(KEY_B) of de.mycompany.entity.model.TableA.listOfBs referencing de.mycompany.entity.model.TableB not mapped to a single property
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1078)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:857)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:84)
at de.mycompany.Start.main(Start.java:14)
Caused by: org.hibernate.AnnotationException: referencedColumnNames(KEY_B) of de.mycompany.entity.model.TableA.listOfBs referencing de.mycompany.entity.model.TableB not mapped to a single property
at org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.java:320)
at org.hibernate.cfg.annotations.CollectionBinder.bindManytoManyInverseFk(CollectionBinder.java:1680)
at org.hibernate.cfg.annotations.CollectionBinder.bindManyToManySecondPass(CollectionBinder.java:1560)
at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:800)
at org.hibernate.cfg.annotations.CollectionBinder.secondPass(CollectionBinder.java:725)
at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:54)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1621)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1589)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:278)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:858)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:885)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:353)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:370)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:359)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624)
... 11 more
这是我的代码:
Table一个
@Entity
@Table(name = "TABLE_A")
public class TableA {
@Id
@Column(name = "KEY", nullable = false)
private int key;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "A_TO_B",
joinColumns = @JoinColumn(name = "KEY_A",
referencedColumnName = "KEY"),
inverseJoinColumns = @JoinColumn(name = "KEY_B",
referencedColumnName = "KEY"))
private List<TableB> listOfBs;
/* More Fields, Getters and setters*/
}
TableB
@Entity
@Table(name = "TABLE_B")
public class TableB {
@EmbeddedId
private TableBId id;
@Column(name = "END_DATE", nullable = false)
private LocalDate endDate;
@ManyToMany(mappedBy = "listOfBs")
private List<TableA> listOfAs;
/* More fields, Getters and Setters*/
}
B 的嵌入式 ID
public class TableBId implements Serializable {
@Column(name = "KEY", nullable = false)
private int key;
@Column(name = "START_DATE", nullable = false)
private LocalDate startDate;
/* Getters and Setters*/
}
Table A 到 B
@Entity
@Table(name = "A_TO_B")
public class AtoB {
@EmbeddedId
private AtoBId id;
/* Getters and Setters*/
}
A 到 B 的嵌入式 ID
public class AtoBId implements Serializable {
@Column(name = "KEY_A", nullable = false)
private int keyA;
@Column(name = "KEY_B", nullable = false)
private int keyB;
/* Getters and Setters */
}
当我用另一个包含日期的假连接列定义 @ManyToMany
时,应用程序启动正常。
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "A_TO_B",
joinColumns = @JoinColumn(name = "KEY_A",
referencedColumnName = "KEY"),
inverseJoinColumns = {@JoinColumn(name = "KEY_B",
referencedColumnName = "KEY"),
@JoinCokumn(name = "SOME_DATE",
referencedColumnName = "START_DATE")})
private List<TableB> listOfBs;
但这不会给我想要的结果。我只想加入 A_TO_B
和 TABLE_B
而不是 KEY_B
。
对于遇到类似问题的任何人,我最后所做的是:
我把A中B的列表做成了transient,也就是说没有保存在DB中。然后我通过 getter:
懒惰地填充它
@Entity
@Configurable
@Table(name = "TABLE_A")
public class TableA {
@Id
@Column(name = "KEY", nullable = false)
private int key;
@Transient
private List<TableB> listOfBs;
@Transient
@Autowired
AtoBRepository aToBRepository;
@Transient
@Autowired
TableBRepository tableBRepository;
public List<TableB> getListOfBs(){
if (listOfBs == null){
listOfBs = new ArrayList<>();
List<AtoB> AtoBs = aToBRepository.findByIdKeyA(key);
for (AtoB aToB : AtoBs){
listOfBs.addAll(tableBRepository.findByIdKey(aToB.getKeyB));
}
}
return listOfBs;
}
/* More Fields, Getters and setters*/
}
要在实体 I 中自动装配存储库,请按此线程中所述加载时间编织:
load Time weaving with @configurable
我通过第三个 table:
在两个 table 之间建立了多对多关系TABLE_A A_TO_B TABLE_B
--------- ------------- ------------
KEY (PK) KEY_A (PK, FK) KEY (PK)
--some more Atributes KEY_B (PK, FK) START_DATE (PK)
--some Attributes END_DATE
--some Attributes
如您所见,此 Table 结构的问题在于 Table B
具有包含条目开始日期的组合主键。这是为了能够有入门版。我无法更改 table 结构。我想通过 @ManyToMany
属性在 JPA 中加入 TABLE_A
和 TABLE_B
。但是 JPA 要求 A_TO_B
知道 TABLE_B
的完整主键。但是我会完全满足于忽略 START_DATE
并只获取 TABLE_B
和 KEY_B
的所有条目以获得特定的 KEY_A
。
这是错误:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [spring_hibernate_configuration.xml]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: referencedColumnNames(KEY_B) of de.mycompany.entity.model.TableA.listOfBs referencing de.mycompany.entity.model.TableB not mapped to a single property
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1078)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:857)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:84)
at de.mycompany.Start.main(Start.java:14)
Caused by: org.hibernate.AnnotationException: referencedColumnNames(KEY_B) of de.mycompany.entity.model.TableA.listOfBs referencing de.mycompany.entity.model.TableB not mapped to a single property
at org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.java:320)
at org.hibernate.cfg.annotations.CollectionBinder.bindManytoManyInverseFk(CollectionBinder.java:1680)
at org.hibernate.cfg.annotations.CollectionBinder.bindManyToManySecondPass(CollectionBinder.java:1560)
at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:800)
at org.hibernate.cfg.annotations.CollectionBinder.secondPass(CollectionBinder.java:725)
at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:54)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1621)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1589)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:278)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:858)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:885)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:353)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:370)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:359)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624)
... 11 more
这是我的代码:
Table一个
@Entity
@Table(name = "TABLE_A")
public class TableA {
@Id
@Column(name = "KEY", nullable = false)
private int key;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "A_TO_B",
joinColumns = @JoinColumn(name = "KEY_A",
referencedColumnName = "KEY"),
inverseJoinColumns = @JoinColumn(name = "KEY_B",
referencedColumnName = "KEY"))
private List<TableB> listOfBs;
/* More Fields, Getters and setters*/
}
TableB
@Entity
@Table(name = "TABLE_B")
public class TableB {
@EmbeddedId
private TableBId id;
@Column(name = "END_DATE", nullable = false)
private LocalDate endDate;
@ManyToMany(mappedBy = "listOfBs")
private List<TableA> listOfAs;
/* More fields, Getters and Setters*/
}
B 的嵌入式 ID
public class TableBId implements Serializable {
@Column(name = "KEY", nullable = false)
private int key;
@Column(name = "START_DATE", nullable = false)
private LocalDate startDate;
/* Getters and Setters*/
}
Table A 到 B
@Entity
@Table(name = "A_TO_B")
public class AtoB {
@EmbeddedId
private AtoBId id;
/* Getters and Setters*/
}
A 到 B 的嵌入式 ID
public class AtoBId implements Serializable {
@Column(name = "KEY_A", nullable = false)
private int keyA;
@Column(name = "KEY_B", nullable = false)
private int keyB;
/* Getters and Setters */
}
当我用另一个包含日期的假连接列定义 @ManyToMany
时,应用程序启动正常。
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "A_TO_B",
joinColumns = @JoinColumn(name = "KEY_A",
referencedColumnName = "KEY"),
inverseJoinColumns = {@JoinColumn(name = "KEY_B",
referencedColumnName = "KEY"),
@JoinCokumn(name = "SOME_DATE",
referencedColumnName = "START_DATE")})
private List<TableB> listOfBs;
但这不会给我想要的结果。我只想加入 A_TO_B
和 TABLE_B
而不是 KEY_B
。
对于遇到类似问题的任何人,我最后所做的是:
我把A中B的列表做成了transient,也就是说没有保存在DB中。然后我通过 getter:
懒惰地填充它@Entity
@Configurable
@Table(name = "TABLE_A")
public class TableA {
@Id
@Column(name = "KEY", nullable = false)
private int key;
@Transient
private List<TableB> listOfBs;
@Transient
@Autowired
AtoBRepository aToBRepository;
@Transient
@Autowired
TableBRepository tableBRepository;
public List<TableB> getListOfBs(){
if (listOfBs == null){
listOfBs = new ArrayList<>();
List<AtoB> AtoBs = aToBRepository.findByIdKeyA(key);
for (AtoB aToB : AtoBs){
listOfBs.addAll(tableBRepository.findByIdKey(aToB.getKeyB));
}
}
return listOfBs;
}
/* More Fields, Getters and setters*/
}
要在实体 I 中自动装配存储库,请按此线程中所述加载时间编织: load Time weaving with @configurable