внешний ключ JPA обновления hibernate
мой 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;
}
Если я изменяю " имя " и вызываю слияние, он может обновляться в базу данных, но когда я изменяю issDivision и вызываю слияние, он не обновляет базу данных. как это решить?
связано ли это с тем, что я использую embededId (составные первичные ключи) ?
обновлено
Если я настроил upadted=true, я получаю ниже error
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.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.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.
3 ответов
Ну, посмотрим
ваше исключение (и известных) сообщение
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 хранит ненулевое значение и accountNumber значение null.
должен ли я выполнить такой запрос ???
INSERT INTO ACCOUNT (ACCOUNT_NUMBER, ACCOUNT_NUMBER) VALUES (127359, NULL);
это не имеет смысла. Следовательно, это неправильный SQL-запрос;
из-за этого, вы видите это хорошее сообщение
повторяющиеся колонки... бла-бла-бла... (должно быть сопоставлено с insert= "false" update= "false")
так я думаю в составном первичном ключе IssTESTPK также хранится столбец SURVEY_NUM. И это не очень хорошая идея свойство составного первичного ключа определяется как insert= "false" update= "false". Избегайте сильной головной боли.
имейте в виду: когда несколько свойств имеют один и тот же столбец, определите один из них как insertable=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
}
}
обновление
перед
спящий режим не поддерживает автоматическая генерация составного первичного ключа
вы должны обеспечить его значения перед сохранением. Имейте это в виду
давайте см. первичный ключ Employee compound
@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º его значения не могут быть null
Так, согласно описанному выше, наш 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 использует его для сохранения нашей сущности
As Hibernate будет использовать наше составное свойство первичного ключа вызванный surveyNumber (и его столбец SURVEY_NUMBER) для выполнения операции SQL над базой данных, нам нужно переписать наше свойство @ManyToOne division (и его столбец внешнего ключа 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, наше свойство division ведет себя как постоянный. Вы, значит, думаете создание нового свойства 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_CODE SURVEY_NUMBER
1 10
2 11
3 12
4 13
5 14
помните: существует ограничение внешнего ключа между подразделением и сотрудником
вы думаете о
я не могу изменить раздел свойство из-за insertable=false, updatable=false. но я могу изменить divisionCode свойство (и его столбец DIVISION_CODE) как способ изменить столбец внешнего ключа, называемый DIVISION_CODE
вы делаете следующий код
сотрудник.setDivisionCode (7);
Wow, см. выше в DIVISION_TABLE. Есть ли какое-то значение в столбце DIVISION_CODE равное 7 ?
ответ ясен: нет (вы увидите нарушение ограничения)
и это непоследовательное отображение. Зимовать не позволяет.
С уважением,
Это потому что вы используете updatable = false
. Удаление его может привести к другим проблемам, которые я не могу предположить, не зная вашего полного отображения.
установить updatable
и insertable
to false
на Embeddable
class, и удалите их из столбцов соединения
Я нашел обходной путь, но мне нравится слышать от вас всех, можно ли использовать эту технику. я изменяю класс сущности на..
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", когда во время merge