我的jpa如下所示
public class TESTClass implements Serializable {
...
private String name;
@EmbeddedId
protected IssTESTPK issTESTPK;
@ManyToOne(optional=false)
@JoinColumns({
@JoinColumn(name="DIVISION_CODE", referencedColumnName="DIVISION_CODE", nullable=false, insertable=false, updatable=false),
@JoinColumn(name="SURVEY_NUM", referencedColumnName="SURVEY_NUM", nullable=false, insertable=false, updatable=false)})
private IssDivision issDivision;
}
如果我更改为'name'并调用merge,它可以更新到数据库,但是当我更改issDivision并调用merge时,它不会更新数据库。怎么解决这个?
它与我有关,因为我使用的是embededId(复合主键)?
如果我设置upadted = true,我得到以下错误
ERROR - ContextLoader.initWebApplicationContext(215) | Context initialization fa
iled
org.springframework.beans.factory.BeanCreationException: Error creating bean wit
h name 'sessionFactory' defined in ServletContext resource [/WEB-INF/application
Context.xml]: Invocation of init method failed; nested exception is org.hibernat
e.MappingException: Repeated column in mapping for entity: com.compay.test.model
.TESTClass column: SURVEY_NUM (should be mapped with insert="false" update="fa
lse")
at org.springframework.beans.factory.support.AbstractAutowireCapableBean
Factory.initializeBean(AbstractAutowireCapableBeanFactory.java:1338)
at org.springframework.beans.factory.support.AbstractAutowireCapableBean
Factory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
at org.springframework.beans.factory.support.AbstractAutowireCapableBean
Factory$1.run(AbstractAutowireCapableBeanFactory.java:409)
at java.security.AccessController.doPrivileged(Native Method)
at org.springframework.beans.factory.support.AbstractAutowireCapableBean
Factory.createBean(AbstractAutowireCapableBeanFactory.java:380)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getOb
ject(AbstractBeanFactory.java:264)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistr
y.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBe
an(AbstractBeanFactory.java:261)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean
(AbstractBeanFactory.java:185)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean
(AbstractBeanFactory.java:164)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.
preInstantiateSingletons(DefaultListableBeanFactory.java:423)
at org.springframework.context.support.AbstractApplicationContext.finish
BeanFactoryInitialization(AbstractApplicationContext.java:728)
at org.springframework.context.support.AbstractApplicationContext.refres
h(AbstractApplicationContext.java:380)
at org.springframework.web.context.ContextLoader.createWebApplicationCon
text(ContextLoader.java:255)
at org.springframework.web.context.ContextLoader.initWebApplicationConte
xt(ContextLoader.java:199)
at org.springframework.web.context.ContextLoaderListener.contextInitiali
zed(ContextLoaderListener.java:45)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContex
t.java:3843)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4
342)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase
.java:791)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:77
1)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:525)
at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.ja
va:627)
at org.apache.catalina.startup.HostConfig.deployDescriptors(HostConfig.j
ava:553)
at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:488
)
at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1149)
at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java
:311)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(Lifecycl
eSupport.java:117)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443
)
at org.apache.catalina.core.StandardService.start(StandardService.java:5
16)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:710
)
at org.apache.catalina.startup.Catalina.start(Catalina.java:578)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
答案 0 :(得分:15)
好吧,让我们看看
您的异常(和着名)消息是
repeated column in mapping for entity:
column: SURVEY_NUM (should be mapped with insert="false" update="false")
SURVEY_NUM栏目在哪里?
1º issDivision字段存储名为SURVEY_NUM的外键列
@ManyToOne
@JoinColumns({
@JoinColumn(name="DIVISION_CODE", referencedColumnName="DIVISION_CODE", insertable=false, updatable=false),
@JoinColumn(name="SURVEY_NUM", referencedColumnName="SURVEY_NUM", insertable=false, updatable=false)})
private IssDivision issDivision;
现在,请参阅以下映射(同时查看id和accountNumber共享同一列)
@Entity
public class Account {
private Integer id;
private Integer accountNumber;
@Id
@Column(name="ACCOUNT_NUMBER")
public Integer getId() {
return this.id;
}
@Column(name="ACCOUNT_NUMBER")
public Integer getAccountNumber() {
return this.accountNumber;
}
}
现在让我们按照以下步骤进行操作
Account account = new Account();
account.setId(127359);
account.setAccountNumber(null);
entityManager.persist(account);
Hibernate会问你
我应该坚持哪个属性两个属性是否共享同一列 ???正如我所看到的,id属性存储一个非null值,accountNumber存储一个空值。
我应该执行像这样的查询???
INSERT INTO ACCOUNT (ACCOUNT_NUMBER, ACCOUNT_NUMBER) VALUES (127359, NULL);
没有意义。因此,这是一个错误的SQL查询;
因此,你会看到这条好消息
重复列...等等,等等,等等...(应使用insert =“false”update =“false”进行映射)
所以我想你的复合主键IssTESTPK也会存储一个名为SURVEY_NUM的列。并且这不是一个好主意您将复合主键属性定义为insert =“false”update =“false”。避免很多头痛。
请记住:当多个属性共享同一列时,请将其中一个定义为insertable = false,updatable = false。 没有别的。
我认为你的复合主键类看起来应该是这个
@Embeddable
public class IssTESTPK implements Serializable {
// Ops... Our missing field which causes our Exception (repeated column... blah, blah, blah...)
@Column(name="SURVEY_NUM", nullable=false)
private Integer property;
private Integer otherProperty;
private Integer anotherProperty;
// required no-arg constructor
public IssTESTPK() {}
// You must implement equals and hashcode
public boolean equals(Object o) {
if(o == null)
return false;
if(!(o instanceof IssTESTPK))
return false;
IssTESTPK other = (IssTESTPK) o;
if(!(getProperty().equals(other.getProperty())))
return false;
if(!(getOtherProperty().equals(other.getOtherProperty())))
return false;
if(!(getAnotherProperty().equals(other.getAnotherProperty())))
return false;
return true;
}
// NetBeans or Eclipse will worry about it
public int hashcode() {
// hashcode code goes here
}
}
<强>更新强>
继续之前
Hibernate 不支持自动生成复合主键
必须在保存之前提供其值。记住它
让我们看一下员工复合主键
@Embeddable
public class EmployeeId implements Serializable {
@Column(name="EMPLOYEE_NUMBER")
private String employeeNumber;
@Column(name="SURVEY_NUMBER")
private BigInteger surveyNumber;
// getter's and setter's
// equals and hashcode
}
1º在保存员工之前,必须提供其值。如上所述,Hibernate不支持自动生成复合主键
2º Hibernate不允许更新(复合)主键它没有意义。
3º其值不能为空
因此,根据上述情况,我们的EmployeeId可以写成
@Embeddable
public class EmployeeId implements Serializable {
@Column(name="EMPLOYEE_NUMBER", nullable=false, updatable=false)
private String employeeNumber;
@Column(name="SURVEY_NUMBER", nullable=false, updatable=false)
private BigInteger surveyNumber;
// getter's and setter's
// equals and hashcode
}
如上所述
当多个属性共享同一列时,将其中一个定义为insertable = false,updatable = false。 没有别的
但我们无法将复合主键属性标记为insertable = false,updatable = false 因为Hibernate使用它来保存我们的实体
由于Hibernate将使用名为surveyNumber(及其SURVEY_NUMBER列)的复合主键属性对数据库执行SQL操作,我们需要重新编写@ManyToOne除法属性(及其外键列名为SURVEY_NUMBER)作为insertable = false,updatable = false
// Employee.java
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumns({
@JoinColumn(name="DIVISION_CODE", referencedColumnName="DIVISION_CODE"),
@JoinColumn(name="SURVEY_NUMBER", referencedColumnName="SURVEY_NUMBER", insertable=false, updatable=false)})
private Division division;
4º当你有一个复合外键时,我们不能混合可插入 - 不可插入或可更新 - 不可更新。
像
这样的东西@ManyToOne(fetch=FetchType.LAZY)
@JoinColumns({
// I can be updatable
@JoinColumn(name="DIVISION_CODE", referencedColumnName="DIVISION_CODE", insertable=false),
// And i can be insertable
@JoinColumn(name="SURVEY_NUMBER", referencedColumnName="SURVEY_NUMBER", updatable=false)})
private Division division;
否则,Hibernate会抱怨
不允许在属性中混合可插入和不可插入的列
因此,它的复合外键列DIVISION_CODE 也应标记为,因为insertable = false,updatable = false以避免上面显示的异常
// Employee.java
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumns({
@JoinColumn(name="DIVISION_CODE", referencedColumnName="DIVISION_CODE", insertable=false, updatable=false),
@JoinColumn(name="SURVEY_NUMBER", referencedColumnName="SURVEY_NUMBER", insertable=false, updatable=false)})
private Division division;
由于我们无法再更新DIVISION_CODE列,因此我们的除法属性的行为类似于常量。然后,您考虑创建一个名为divisionCode的新属性,以便更改DIVISION_CODE列,如下所示
// Employee.java
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumns({
@JoinColumn(name="DIVISION_CODE", referencedColumnName="DIVISION_CODE", insertable=false, updatable=false),
@JoinColumn(name="SURVEY_NUMBER", referencedColumnName="SURVEY_NUMBER", insertable=false, updatable=false)})
private Division division;
// Wow, now i expect i can change the value of DIVISION_CODE column
@Column(name="DIVISION_CODE")
private BigInteger divisionCode;
好吧,我们来看看。假设我们有以下DIVISION TABLE
DIVISION TABLE
DIVISION_CODE SURVEY_NUMBER
1 10
2 11
3 12
4 13
5 14
请记住:Division和Employee之间存在外键约束
你想到
由于insertable = false,updatable = false,我无法更改除法属性。 但我可以更改divisionCode 属性(及其DIVISION_CODE列)作为更改名为DIVISION_CODE的外键列的方法
您执行以下代码
employee.setDivisionCode(7);
哇,见上面的DIVISION_TABLE。 DIVISION_CODE列中的某些值是否等于7?答案很清楚:不(你会看到一个约束违规)
所以,这是一个不一致的映射。 Hibernate不允许它。
的问候,
答案 1 :(得分:2)
这是因为您正在使用updatable = false
。删除它可能会导致其他问题,我不能假设你不知道你的完整映射。
将updatable
和insertable
设置为false
类中的Embeddable
,并将其从连接列中删除
答案 2 :(得分:1)
我找到了解决方法,但我想听听大家是否可以使用这种技术。我将实体类修改为..
public class TESTClass implements Serializable {
...
private String name;
@EmbeddedId
protected IssTESTPK issTESTPK;
@JoinColumns({@JoinColumn(name = "DIVISION_CODE", referencedColumnName = "DIVISION_CODE", nullable = false , insertable = false, updatable = false), @JoinColumn(name = "SURVEY_NUM", referencedColumnName = "SURVEY_NUM", nullable = false, insertable = false, updatable = false)})
@ManyToOne(optional = false)
private IssDivision issDivision; //since this is not merge
@Basic(optional = false)
@Column(name = "DIVISION_CODE")
private String divisionCode; //i add this
}
我添加了'divisionCode'属性,即使它在issDivision对象内部重复。但这是我在合并期间能够更新'DIVISION_CODDE'的解决方法