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",updatable=false)}) private IssDivision issDivision; }
如果我更改为’name’并调用merge,它可以更新到数据库,但是当我更改issDivision并调用merge时,它不会更新数据库. X- 20045 X- 20045 X- 20045 X- 20045 200:
这是否与我使用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.
解决方法
你的例外(和着名的)消息是
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",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会问你
Which property should i persist whether both properties shares the same column ??? And as i can see,id property stores a non-null value and accountNumber a null value.
我应该像这样执行一个查询吗?
INSERT INTO ACCOUNT (ACCOUNT_NUMBER,ACCOUNT_NUMBER) VALUES (127359,NULL);
因为这样,你看到这个好消息
repeated column… blah,blah,blah… (should be mapped with 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...) @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 } }
UPDATE
在继续之前
Hibernate does not support automatic generation of compound primary key
保存前必须提供其值.记住它
我们来看看员工复合主键
@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",updatable=false) private String employeeNumber; @Column(name="SURVEY_NUMBER",updatable=false) private BigInteger surveyNumber; // getter's and setter's // equals and hashcode }
如上所述
when more than one property shares the same column,define one of them as insertable=false,updatable=false. Nothing else
但是我们不能将复合主键属性标记为insertable = false,updatable = false,因为Hibernate使用它来保存我们的实体
由于Hibernate将使用名为surveyNumber(及其SURVEY_NUMBER列)的复合主键属性来对数据库执行sql操作,因此我们需要将@ManyToOne除法属性(及其外键列名为SURVEY_NUMBER)重写为可插入= false,可更新= FALSE
// Employee.java @ManyToOne(fetch=FetchType.LAZY) @JoinColumns({ @JoinColumn(name="DIVISION_CODE",referencedColumnName="DIVISION_CODE"),@JoinColumn(name="SURVEY_NUMBER",referencedColumnName="SURVEY_NUMBER",updatable=false)}) private Division division;
4º当您有复合外键时,我们无法混合可插入或不可更新 – 不可更新.
就像是
@ManyToOne(fetch=FetchType.LAZY) @JoinColumns({ // I can be updatable @JoinColumn(name="DIVISION_CODE",insertable=false),// And i can be insertable @JoinColumn(name="SURVEY_NUMBER",updatable=false)}) private Division division;
否则,Hibernate会抱怨
Mixing insertable and non insertable columns in a property is not allowed
因此,名为DIVISION_CODE的复合外键列也应标记为insertable = false,updatable = false以避免上述异常
// Employee.java @ManyToOne(fetch=FetchType.LAZY) @JoinColumns({ @JoinColumn(name="DIVISION_CODE",updatable=false)}) private Division division;
由于我们无法更新DIVISION_CODE列,我们的division属性的行为就像一个常量.那么,您可以想像创建一个名为divisionCode的新属性来改变DIVISION_CODE列,如下所示
// Employee.java @ManyToOne(fetch=FetchType.LAZY) @JoinColumns({ @JoinColumn(name="DIVISION_CODE",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之间有一个外键约束
你想到了
I can not change division property because of insertable=false,updatable=false. But i can change divisionCode property (and its DIVISION_CODE column) as a way to change the foreign key column called DIVISION_CODE
您执行以下代码
employee.setDivisionCode(7);
哇,见上面的DIVISION_TABLE. DIVISION_CODE列中的某些值是否等于7?
答案很清楚:否(你会看到约束违规)
所以,这是一个不一致的映射. Hibernate不允许.
问候,