こんばんは。
Hibernate を処理する方法を理解しようとしています。私のテストでは、Hibernate 継承を使用していますが、これは私が持っている例外です:
Hibernate: select theuser0_.ID as ID1_2_0_, theuser0_.FIRST_NAME as FIRST_NA3_2_0_, theuser0_.LAST_NAME as LAST_NAM4_2_0_, theuser0_.PASSWORD as PASSWORD5_2_0_, theuser0_.EMALE as EMALE6_2_0_, theuser0_.GENDER as GENDER7_2_0_, theuser0_.UCI_PERSON_ADDRESS as UCI_PERS8_2_0_, theuser0_.UCI_PERSON_PHONE as UCI_PERS9_2_0_, theuser0_.USER_INFO_TYPE as USER_INF2_2_0_ from USER theuser0_ where theuser0_.ID=?
Hibernate: insert into USER_EVENTS (EVENT_DATE, USER_ID, EVENT_INDEX) values (?, ?, ?)
Oct 07, 2013 2:51:53 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 1062, SQLState: 23000
Oct 07, 2013 2:51:53 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: Duplicate entry '1' for key 'UK_tbce3olw19taxx6srova86xok'
Exception in thread "main" org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.springframework.orm.hibernate4.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:138)
at org.springframework.orm.hibernate4.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:680)
at org.springframework.orm.hibernate4.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:562)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:755)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:724)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:475)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:270)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at com.sun.proxy.$Proxy7.saveUser(Unknown Source)
at demidov.pkg.persistence.AppOut.main(AppOut.java:36)
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:74)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:136)
at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:96)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:58)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2975)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3487)
at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:81)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:377)
at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:214)
at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:194)
at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:178)
at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:321)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:286)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:192)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:206)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:191)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:114)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:735)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:727)
at org.hibernate.engine.spi.CascadingAction$5.cascade(CascadingAction.java:258)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:388)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:331)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:209)
at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:418)
at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:358)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:334)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:209)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:166)
at org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:162)
at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:153)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:89)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1234)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:404)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
at org.springframework.orm.hibernate4.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:554)
... 9 more
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '1' for key 'UK_tbce3olw19taxx6srova86xok'
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.Util.getInstance(Util.java:386)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1041)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4190)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4122)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2570)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2731)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2818)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2157)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2460)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2377)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2361)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:133)
... 46 more
私は 2 つの親エンティティを持っています。1 つ目は、サブクラス UserInfo を持つ TheUser です。
public class TheUser {
private int userId;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
private String userFirstName;
public String getUserFirstName() {
return userFirstName;
}
public void setUserFirstName(String userFirstName) {
this.userFirstName = userFirstName;
}
private String userLastName;
public String getUserLastName() {
return userLastName;
}
public void setUserLastName(String userLastName) {
this.userLastName = userLastName;
}
private String userPassword;
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
private String userEmale;
public String getUserEmale() {
return userEmale;
}
public void setUserEmale(String userEmale) {
this.userEmale = userEmale;
}
private String userGender;
public String getUserGender() {
return userGender;
}
public void setUserGender(String userGender) {
this.userGender = userGender;
}
private List<UserEvents> userEventsList = new ArrayList<UserEvents>();
public List<UserEvents> getUserEventsList() {
return userEventsList;
}
public void setUserEventsList(List<UserEvents> userEventsList) {
this.userEventsList = userEventsList;
}
これは、TheUser の xml マッピングです。
<class name="demidov.pkg.domain.TheUser" table="USER">
<id name="userId" column="ID">
<generator class="native"/>
</id>
<discriminator column="USER_INFO_TYPE" type="string"/>
<property name="userFirstName" column="FIRST_NAME" type="string"/>
<property name="userLastName" column="LAST_NAME" type="string"/>
<property name="userPassword" column="PASSWORD" type="string"/>
<property name="userEmale" column="EMALE" type="string"/>
<property name="userGender" column="GENDER" type="string"/>
<list name="userEventsList" inverse="false" lazy="true" fetch="select" cascade="all" >
<key column="USER_ID" not-null="true" />
<index column="EVENT_INDEX" />
<one-to-many class="demidov.pkg.domain.UserEvents"/>
</list>
<subclass name="demidov.pkg.domain.UserContactInfo" discriminator-value="UCI" >
<property name="personAddress" column="UCI_PERSON_ADDRESS" />
<property name="personPhoneNumber" column="UCI_PERSON_PHONE" />
</subclass>
</class>
サブクラスを持つ UserEvents: ComputerMaintenanceEvent および SoftwareDevelopmentEvent エンティティ:
public class UserEvents {
private int userEventId;
public int getUserEventId() {
return userEventId;
}
public void setUserEventId(int userEventId) {
this.userEventId = userEventId;
}
private Date userEventDate;
public Date getUserEventDate() {
return userEventDate;
}
public void setUserEventDate(Date userEventDate) {
this.userEventDate = userEventDate;
}
protected TheUser theUser;
public TheUser getTheUser() {
return theUser;
}
public void setTheUser(TheUser theUser) {
this.theUser = theUser;
}
}
userevent の xml マッピングを使用:
<hibernate-mapping>
<class name="demidov.pkg.domain.UserEvents" table="USER_EVENTS">
<id name="userEventId" column="ID" type="integer">
<generator class="native"/>
</id>
<property name="userEventDate" column="EVENT_DATE" type="date"/>
<many-to-one name="theUser" class="demidov.pkg.domain.TheUser" insert="false" update="false" lazy="false" fetch="select" cascade="save-update">
<column name="USER_ID" not-null="true" unique="true" />
</many-to-one>
<joined-subclass name="demidov.pkg.domain.ComputerMaintenanceEvent" table="MAINTENANCE_EVENT">
<key column="MAINTENANCE_ID" not-null="true"/>
<property name="descriptionMaintenance" column="DESCRIPTION_MAINTENANCE" type="string"/>
<property name="additionalInfoMaintenance" column="ADDITIONAL_INFO_MAINTENANCE" type="string"/>
</joined-subclass>
<joined-subclass name="demidov.pkg.domain.SoftwareDevelopmentEvent" table="DEVELOPMENT_EVENT">
<key column="DEVELOPMENT_ID" not-null="true"/>
<property name="descriptionDevelopment" column="DESCRIPTION_DEVELOPMENT" type="string"/>
<property name="additionalInfoDevelopment" column="ADDITIONAL_INFO_DEVELOPMENT" type="string"/>
</joined-subclass>
</class>
</hibernate-mapping>
データベースには、すでにデータが一度挿入されています。
TheUser エンティティ + サブクラス = 継承 階層ごとのテーブル:
+----+----------------------------+------------+-----------+----------+-----------------+--------+--------------------+------------------+
| ID | USER_INFO_TYPE | FIRST_NAME | LAST_NAME | PASSWORD | EMALE | GENDER | UCI_PERSON_ADDRESS | UCI_PERSON_PHONE |
+----+----------------------------+------------+-----------+----------+-----------------+--------+--------------------+------------------+
| 1 | demidov.pkg.domain.TheUser | Vadim | Demidov | 123123 | vadim@google.ru | Male | NULL | NULL |
+----+----------------------------+------------+-----------+----------+-----------------+--------+--------------------+------------------+
UserEvents とサブクラスの間: SoftwareDevelopmentEvent と ComputerMaitnanceEvent は、サブクラス継承ごとのテーブルです。
DB の UserEvents テーブル:
+----+------------+---------+-------------+
| ID | EVENT_DATE | USER_ID | EVENT_INDEX |
+----+------------+---------+-------------+
| 1 | 2013-10-07 | 1 | 0 |
+----+------------+---------+-------------+
UserEvents のサブクラス - SoftwareDevelopmentEvent:
+----------------+-------------------------+-----------------------------+
| DEVELOPMENT_ID | DESCRIPTION_DEVELOPMENT | ADDITIONAL_INFO_DEVELOPMENT |
+----------------+-------------------------+-----------------------------+
| 1 | Create website | Create news portal |
+----------------+-------------------------+-----------------------------+
既存のユーザーに新しいイベントを追加しようとしています:
public void saveUser(Integer id, List<UserEvents> listEvents) {
Session session = sessionFactory.getCurrentSession();
TheUser theuser = (TheUser)session.get(TheUser.class, id);
theuser.setUserEventsList(listEvents);
session.saveOrUpdate(theuser);
}
主な方法:
List<UserEvents> eventsList = new ArrayList<UserEvents>();
ComputerMaintenanceEvent sde = new ComputerMaintenanceEvent();
sde.setDescriptionMaintenance("Fix PC");
sde.setAdditionalInfoMaintenance("Fix my PC please");
sde.setUserEventDate(new Date());
eventsList.add(sde);
dao.saveUser(1, eventsList);
助けてください。よろしくお願いいたします。
^解決済みの問題:問題は userevent.hbm.xml にあり、unique="true" を誤ってリレーションシップに設定してしまいました。
みんなありがとう。