"User" エンティティは、"Car" の 1 対多の双方向関係です。"Car" エンティティは、"CarPhoto" エンティティ ("Photo" エンティティの継承) の 1 対多の双方向関係です。「Car」エンティティには、「CarPhoto」との 1 対 1 の関係もあります。
したがって、CarPhotos は車の写真であり、車は、これらの写真のいずれかがカバー写真になるかどうかも示します (1 つの写真がアルバムの前面に表示されるアルバムのように考えてください)。
この問題は、カバー写真が設定されている場合に発生します。
以下の私のコードとエラーメッセージを見てください:
@Entity
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "USERS_SEQ")
@TableGenerator(name = "USERS_SEQ", table = "SEQUENCE", pkColumnName = "SEQ_NAME", pkColumnValue = "USERS_SEQ", valueColumnName = "SEQ_COUNT", allocationSize = 1)
@Column(nullable = false)
private long id;
@OneToMany(mappedBy = "user", cascade = { CascadeType.ALL }, orphanRemoval = true, fetch = FetchType.LAZY)
private Set<Car> cars;
//...
}
@Entity
public class Car {
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "CARS_SEQ")
@TableGenerator(name = "CARS_SEQ", table = "SEQUENCE", pkColumnName = "SEQ_NAME", pkColumnValue = "CARS_SEQ", valueColumnName = "SEQ_COUNT", allocationSize = 1)
@Column(nullable = false)
private long id;
@OneToMany(mappedBy = "car", cascade = { CascadeType.ALL }, fetch = FetchType.LAZY, orphanRemoval = true)
private Set<CarPhoto> photos;
// coverPhoto shall be NULL or a object in the Set<CarPhoto> photos
@OneToOne
@JoinColumn(name = "COVER_PHOTO", referencedColumnName = "ID")
private CarPhoto coverPhoto;
//...
}
@Entity
@DiscriminatorValue("C")
public class CarPhoto extends Photo {
@ManyToOne(cascade = { CascadeType.DETACH })
@JoinColumn(name = "CARID", nullable = false)
@NotNull
private Car car;
//...
}
@Entity
@Inheritance
@DiscriminatorColumn(name = "DESCRIMINATOR")
public abstract class Photo {
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "PHOTOS_SEQ")
@TableGenerator(name = "PHOTOS_SEQ", table = "SEQUENCE", pkColumnName = "SEQ_NAME", pkColumnValue = "PHOTOS_SEQ", valueColumnName = "SEQ_COUNT", allocationSize = 50)
@Column(nullable = false)
private long id;
//...
}
@Test
public void testCarAddCarPhotos() throws Exception {
User user = dg.getTestUser(); // Get a user object
Car car = dg.getTestCar(); // Get a car object
CarPhoto photo = dg.getTestCarPhoto(); // Get a car photo object
user.addToCars(car); // Add car to user cars list
car.setUser(user); // ^^^ To keep bi-directional relationship^^^
photo.setCar(car); // Add car as owner to this photo
car.addToPhotos(photo); // ^^^ To keep bi-directional relationship^^^
em.persist(user);
em.flush();
em.clear();
// This tests works perfectly, the user has a car, and the car has a photo
}
@Test
public void testCarAddCarPhotosAddCoverPhoto() throws Exception {
User user = dg.getTestUser(); // Get a user object
Car car = dg.getTestCar(); // Get a car object
CarPhoto photo = dg.getTestCarPhoto(); // Get a car photo object
user.addToCars(car); // Add car to user cars list
car.setUser(user); // ^^^ To keep bi-directional relationship^^^
photo.setCar(car); // Add car as owner to this photo
car.addToPhotos(photo); // ^^^ To keep bi-directional relationship^^^
// NOW TEST TO A THE COVERPHOTO
car.setCoverPhoto(photo);
em.persist(user);
em.flush();
// ERROR:
// javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.4.0.v20120608-r11652): org.eclipse.persistence.exceptions.DatabaseException
// Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`vehicledb_test`.`PHO
// TOS`, CONSTRAINT `FK_PHOTOS_CARID` FOREIGN KEY (`CARID`) REFERENCES `CARS` (`ID`))
// Error Code: 1452
// Call: INSERT INTO PHOTOS (ID, DESCRIPTION, FILENAME, TITLE, UPLOADTIME, CARID, DESCRIMINATOR) VALUES (?, ?, ?, ?, ?, ?, ?)
// bind => [1, jequejnnzkxhzahaimg, rabbit, computer, 2013-05-16 21:59:42.524, 3, C]
// Query: WriteObjectQuery(Photo [id=1, description=jequejnnzkxhzahaimg, fileName=rabbit, title=computer, uploadTime=Thu May 16 21:59:42 CEST 2013])
// at org.eclipse.persistence.internal.jpa.EntityManagerImpl.flush(EntityManagerImpl.java:804)
// at se.while_se.service.jpa.UserRepositoryTest.testModifyUserRemoveCarWithPhoto(UserRepositoryTest.java:251)
// at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
// at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
// at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
// at java.lang.reflect.Method.invoke(Method.java:601)
// at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
// at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
// at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
// at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
// at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
// at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
// at org.junit.rules.TestWatchman$1.evaluate(TestWatchman.java:48)
// at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
// at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
// at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
// at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
// at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
// at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
// at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
// at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
// at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
// at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
// at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
// at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:35)
// at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:146)
// at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:97)
// at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
// at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
// at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
// at java.lang.reflect.Method.invoke(Method.java:601)
// at org.apache.maven.surefire.booter.ProviderFactory$ClassLoaderProxy.invoke(ProviderFactory.java:103)
// at $Proxy0.invoke(Unknown Source)
// at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:145)
// at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcess(SurefireStarter.java:87)
// at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:69)
// Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.4.0.v20120608-r11652): org.eclipse.persistence.exceptions.DatabaseException
em.clear();
// This test does not works =(
}
追加情報: eclipselink 2.4.0、mysql-connector-java 5.1.20、および Java 7 を実行しています。
どこに問題があるか分かりますか?私を助けてください、私は今これに何日も苦労しています =(((
よろしく、カール