gpt4 book ai didi

java - 如何使用 JPA 将嵌入式类的属性映射到单个数据库列?

转载 作者:行者123 更新时间:2023-11-30 08:47:50 25 4
gpt4 key购买 nike

由于标题可能有点不清楚,我会在这里解释很多。

我有一个用 JPA 映射的实体。在这个实体中,我使用了一个包含属性的可嵌入类。问题是我想将这两个属性映射到同一个数据库列上(示例在后面)。为实现这一点,我重写了这两个属性并将它们映射到列,并且对于其中一个我使用了 insertable = false 和 updatable = false。

事情是行不通的(得到“重复的列映射......”而且我找不到解决这个问题的方法。我也没有找到有类似问题的人。我希望我搜索得很好但是我搜索了很多,我觉得没问题。

供您引用,我正在使用 JPA 2.1 和 Hibernate 实现(但我不想使用 Hibernate 的特定功能)。

这是我的这个类的源代码。问题出在代表一个时期(多种类型:月、年)的“Periode”对象上。问题是我想使用此类来表示年份(作为整数存储在数据库中的单个列中),因此能够访问 Periode 开始和结束日期属性。

Periode 来自遗留代码,我对它的“权力”相对有限(因为它在许多其他项目中使用)。数据库也是遗留的,所以我无法更改它以放置两个日期而不仅仅是年份。

@SuppressWarnings("serial")
@Embeddable
public class CandidateId implements Serializable {
// Fields
private Periode period;
private IdentifiantContrat contractId;

// Constructors
@SuppressWarnings("unused")
private CandidateId() {}

public CandidateId(Periode period, IdentifiantContrat contractId) {
this.period = period;
this.contractId = contractId;
}

public CandidateId(Periode period, IdentifiantAffilie employerId) {
this(period, new IdentifiantContrat(employerId, 0));
}

// Getters
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "debut", column = @Column(name = "PERIODE", nullable = false) ),
@AttributeOverride(name = "fin", column = @Column(name = "PERIODE", nullable = false, insertable = false, updatable = false))
})
// @Converts({
// @Convert(attributeName = "debut", converter = FiscalStartDateConverter.class),
// @Convert(attributeName = "fin", converter = FiscalEndDateConverter.class)
// })
public Periode getPeriod() {
return period;
}

@Embedded
public IdentifiantContrat getContractId() {
return contractId;
}

// Setters
public void setPeriod(Periode period) {
this.period = period;
}

public void setContractId(IdentifiantContrat contractId) {
this.contractId = contractId;
}

// Methods
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((contractId == null) ? 0 : contractId.hashCode());
result = prime * result + ((period == null) ? 0 : period.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CandidateId other = (CandidateId) obj;
if (contractId == null) {
if (other.contractId != null)
return false;
} else if (!contractId.equals(other.contractId))
return false;
if (period == null) {
if (other.period != null)
return false;
} else if (!period.equals(other.period))
return false;
return true;
}

@Override
public String toString() {
return "CandidatDeclarationId [period=" + period + ", contractId=" + contractId + "]";
}
}

如您所见,我计划使用转换器将 int 值从 db 转换为两个匹配的日期,但一次一个问题。

在测试我的代码时,我得到以下信息:

javax.persistence.PersistenceException: [PersistenceUnit: belgium-fiscal-model] Unable to build Hibernate SessionFactory
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:1249)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.access$600(EntityManagerFactoryBuilderImpl.java:120)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:860)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850)
at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:425)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:849)
at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:75)
at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:54)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)
at be.groups.kernel.utils.persistence.JpaUtil.initEntityManagerFactory(JpaUtil.java:168)
at be.groups.kernel.utils.persistence.JpaUtil.createEntityManagerFactory(JpaUtil.java:65)
at be.groups.belgium.fiscal.model.services.CandidateServiceTest.setUp(CandidateServiceTest.java:54)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: be.groups.belgium.fiscal.model.domain.Candidate column: PERIODE (should be mapped with insert="false" update="false")
at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:709)
at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:750)
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:506)
at org.hibernate.mapping.RootClass.validate(RootClass.java:270)
at org.hibernate.cfg.Configuration.validate(Configuration.java:1360)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1851)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:857)
... 25 more

java.lang.NullPointerException
at be.groups.belgium.fiscal.model.services.CandidateServiceTest.tearDown(CandidateServiceTest.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:33)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

如果有什么不清楚的地方,请告诉我,我会尽量精确。

编辑:这是 OndrejM 要求的 Candidate 类。但我不认为问题出在它身上(我已经检查过了,虽然我想念它抱歉^^)。但也许我遗漏了一些东西,所以如果它能有所帮助,那就来上课吧!

@Entity
@Table(name = "ECHEANCIER_FISCAL_PERSONNE")
public class Candidate {
// Fields
private CandidateId id;

private Date datePassage;
private String justification;

private Integer actionProgramme;
private Integer actionGestionnaire;

private BaseSignaturePersistance persistenceSignature;

// Constructors
private Candidate() {}

// Getters
@EmbeddedId
public CandidateId getId() {
return id;
}

@Column(name = "ACTION_PROGRAMME", nullable = true)
public Integer getActionProgramme() {
return actionProgramme;
}

@Column(name = "ACTION_GESTIONNAIRE", nullable = true)
public Integer getActionGestionnaire() {
return actionGestionnaire;
}

@Column(name = "DT_PASSAGE", nullable = true)
public Date getDatePassage() {
return datePassage;
}

@Column(name = "JUSTIFICATION", nullable = true)
public String getJustification() {
return justification;
}

@Embedded
public BaseSignaturePersistance getPersistenceSignature() {
return persistenceSignature;
}

// Setters
public void setId(CandidateId id) {
this.id = id;
}

public void setActionProgramme(Integer actionProgramme) {
this.actionProgramme = actionProgramme;
}

public void setActionGestionnaire(Integer actionGestionnaire) {
this.actionGestionnaire = actionGestionnaire;
}

public void setDatePassage(Date datePassage) {
this.datePassage = datePassage;
}

public void setJustification(String justification) {
this.justification = justification;
}

public void setPersistenceSignature(BaseSignaturePersistance persistenceSignature) {
this.persistenceSignature = persistenceSignature;
}

// Methods
/**
* Tells if this concerns a single contract or not
*
* @return true if this concerns a single contract, else false
*
* @since 1.0.0
*/
@Transient
public boolean isSingleContract() {
return id.getContractId().getNumero() != 0;
}

/**
* Tells if this concerns an employer (multiple contracts) or not
*
* @return true if this concerns an employer, else false
*
* @since 1.0.0
*/
@Transient
public boolean isWholeEmployer() {
return !isSingleContract();
}

/**
* Tells if the candidate is blocked
*
* @return true if this is blocked, else false
*
* @since 2.0.0
*/
@Transient
public boolean isBlocked() {
return actionGestionnaire == null
? (actionProgramme == null || actionProgramme == StatutCloture.PAS_PRET_POUR_PREPARATION.getValeur())
: (actionGestionnaire == StatutCloture.PAS_PRET_POUR_PREPARATION.getValeur());
}
}

这也是嵌入在 Candidate 类中的 BaseSignaturePersistence 类。很抱歉混合了英语和法语代码,但正如我所说,我使用遗留代码,所以一些类(class)是法语的(最近才决定使用英语)。

@Embeddable            
public class BaseSignaturePersistance {

/**
* Auteur creation des données.
*/
private String auteurCreation;
/**
* Auteur modification des données.
*/
private String auteurModification;
/**
* Date creation des données
*/
private Date dateCreation;
/**
* Date modification des données.
*/
private Date dateModification;

/**
* Nouvel Objet Signature.
*
* @param lAuteurCreation
* @param lDateCreation
* @param lAuteurModification
* @param lDateModification
*/
@Requires("auteurCreation!=null && dateCreation!=null")
@Ensures({"this.auteurCreation == auteurCreation && this.dateCreation == dateCreation",
"this.dateModification!=null ? this.auteurModification!=null : true",
"this.auteurModification!=null ? this.dateModification!=null : true"})
public BaseSignaturePersistance(String auteurCreation, Date dateCreation, String auteurModification, Date dateModification) {
this.auteurCreation = auteurCreation;
this.dateCreation = dateCreation;
this.auteurModification = auteurModification;
this.dateModification = dateModification;
}

/**
* Nouvel objet signature contenant seulement la partie creation
* @param unAuteurCreation
* @param uneDateCreation
*/
@Requires({
"unAuteurCreation!=null",
"uneDateCreation!=null"
})
public BaseSignaturePersistance(String unAuteurCreation, Date uneDateCreation){
this(unAuteurCreation, uneDateCreation, null, null);
}

/**
* Nouvel objet signature contenant seulement la partie creation
* @param unAuteurCreation
*/
@Requires({
"auteurCreation!=null"
})
public BaseSignaturePersistance(String unAuteurCreation){
this(unAuteurCreation, DateUtility.getNow(), null, null);
}

/**
* Nouvel objet signature.
* Utiliser setModification ou SetSuppression pour compléter ce qui est nécessaire.
*/
public BaseSignaturePersistance(){
this.auteurCreation = null;
this.dateCreation = null;
this.auteurModification = null;
this.dateModification = null;
}

/**
* Affecte {@code auteur} et {@code date} à {@code auteurModification} et {@code dateModification}.
*
* @param auteur
* @param date
*/
@Requires("auteur!=null && date!=null")
@Ensures("auteurModification == auteur && dateModification == date")
public void setModification(String auteur, Date date) {
auteurModification = auteur;
dateModification = date;
}

public void copy(BaseSignaturePersistance other) {
auteurCreation = other.auteurCreation;
dateCreation = other.dateCreation;
auteurModification = other.auteurModification;
dateModification = other.dateModification;
}

@Column(name = "AUTEUR_CREATION", nullable = false)
public String getAuteurCreation() {
return auteurCreation;
}

@Column(name = "AUTEUR_MODIFICATION")
public String getAuteurModification() {
return auteurModification;
}

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "DT_CREATION", nullable = false)
public Date getDateCreation() {
return dateCreation;
}

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "DT_MODIFICATION")
public Date getDateModification() {
return dateModification;
}

public void setAuteurCreation(String auteurCreation) {
this.auteurCreation = auteurCreation;
}

public void setAuteurModification(String auteurModification) {
this.auteurModification = auteurModification;
}

public void setDateCreation(Date dateCreation) {
this.dateCreation = dateCreation;
}

public void setDateModification(Date dateModification) {
this.dateModification = dateModification;
}

/**
* Gives most recent date the object has been modified
*
* @return modification date if any, else creation date
*/
@Transient
public Date getDateDerniereModification() {
return dateModification != null ? dateModification : dateCreation;
}

/**
* Gives most recent author that has modified the object
*
* @return modification author if any, else creation author
*/
@Transient
public String getAuteurDerniereModification() {
return auteurModification != null ? auteurModification : auteurCreation;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((auteurCreation == null) ? 0 : auteurCreation.hashCode());
result = prime
* result
+ ((auteurModification == null) ? 0 : auteurModification
.hashCode());
result = prime * result
+ ((dateCreation == null) ? 0 : dateCreation.hashCode());
result = prime
* result
+ ((dateModification == null) ? 0 : dateModification.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
BaseSignaturePersistance other = (BaseSignaturePersistance) obj;
if (auteurCreation == null) {
if (other.auteurCreation != null)
return false;
} else if (!auteurCreation.equals(other.auteurCreation))
return false;
if (auteurModification == null) {
if (other.auteurModification != null)
return false;
} else if (!auteurModification.equals(other.auteurModification))
return false;
if (dateCreation == null) {
if (other.dateCreation != null)
return false;
} else if (!dateCreation.equals(other.dateCreation))
return false;
if (dateModification == null) {
if (other.dateModification != null)
return false;
} else if (!dateModification.equals(other.dateModification))
return false;
return true;
}

@Override
public String toString() {
return "BaseSignaturePersistance [auteurCreation=" + auteurCreation
+ ", auteurModification=" + auteurModification
+ ", dateCreation=" + dateCreation + ", dateModification="
+ dateModification + "]";
}
}

最佳答案

我没有发现您的代码有问题。唯一不常见的是您将嵌入式 ID 的两个属性映射到单个列,但我看不出有什么问题。

然而,事实是hibernate不支持嵌入式主键中的这种映射(可能是一个bug)。我检查了 hibernate 的代码,发现嵌入式 ID 不考虑可插入/可更新,只考虑属性。比较代码如何properties are checked以及 primary key are checked 的列(第 750 行)。

现在一个可能的解决方案:

尝试从 CandidadeId 中删除 Periode 类,并将 PERIODE 列单独映射到一个新字段。然后将 Periode 类直接嵌入到 Candidate 实体中,并将​​映射到 PERIODE 列的两个属性的属性覆盖为只读(可插入/可更新 = false)。

这将从主键中删除遗留实体 Periode,并且仍然可以从实体 Candidate 中使用它。缺点是您不能修改 Periode 类,而总是需要修改 CandidateId 上的 period 字段。但是,您可以创建一个预更新监听器,并在实体持久化之前将 Periode 类的值复制到新的期间字段中。

类似下面的内容(我在字段而不是属性上使用映射以使其更具可读性):

@Embeddable
public class CandidateId implements Serializable {
@Column(name = "PERIODE")
// instead of class Periode put here field period of the same type as field debut in class Periode
private Date period;


@Table(name = "ECHEANCIER_FISCAL_PERSONNE")
public class Candidate {
// Fields
@EmbeddedId
private CandidateId id;
// add following:
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "debut", column = @Column(name = "PERIODE", nullable = false, insertable = false, updatable = false) ),
@AttributeOverride(name = "fin", column = @Column(name = "PERIODE", nullable = false, insertable = false, updatable = false))
})
Periode period;

关于java - 如何使用 JPA 将嵌入式类的属性映射到单个数据库列?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32250542/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com