在关系的两边声明@OneToOne和@NotNull是否有效,例如:
class ChangeEntry
{
@OneToOne(cascade=CascadeType.ALL)
@NotNull
ChangeEntryDetails changeEntryDetails;
public void addDetails(ChangeEntryDetails details) {
this.changeEntryDetails = details;
details.setChangeEntry(this);
}
}
class ChangeEntryDetails
{
@OneToOne(cascase=CascadeType.ALL)
@NotNull
ChangeEntry changeEntry;
public void setChangeEntry(ChangeEntry changeEntry)
{
this.changeEntry = changeEntry;
}
}我找不到任何东西说这是无效的,但似乎在坚持期间,至少有一方的关系必须被违反。(例如,如果首先写入changeEntry,则changeEntryDetails暂时为空)。
在尝试此操作时,我看到一个异常抛出not-null property references a null or transient value。
如果可能的话,我想避免放松约束,因为双方都必须在场。
发布于 2010-04-28 01:11:06
在关系的两边声明
@OneToOne和@NotNull是否有效(.)我找不到任何东西说这是无效的,但似乎在坚持期间,至少有一方的关系必须被违反。(例如,如果首先写入changeEntry,则changeEntryDetails暂时为空)。
它是有效的,每件事都能很好地处理映射好的实体。您需要将双向关联的一方声明为“拥有”方(此“控件”为插入顺序)。一个可能的工作解决办法是:
@Entity
@NamedQueries( { @NamedQuery(name = ChangeEntry.FIND_ALL_CHANGEENTRIES, query = "SELECT c FROM ChangeEntry c") })
public class ChangeEntry implements Serializable {
public final static String FIND_ALL_CHANGEENTRIES = "findAllChangeEntries";
@Id
@GeneratedValue
private Long id;
@OneToOne(optional = false, cascade = CascadeType.ALL)
@JoinColumn(name = "DETAILS_ID", unique = true, nullable = false)
@NotNull
private ChangeEntryDetails changeEntryDetails;
public void addDetails(ChangeEntryDetails details) {
this.changeEntryDetails = details;
details.setChangeEntry(this);
}
// constructor, getters and setters
}对于另一个实体(请注意在关联的非拥有方设置的mappedBy属性):
@Entity
public class ChangeEntryDetails implements Serializable {
@Id
@GeneratedValue
private Long id;
@OneToOne(optional = false, mappedBy = "changeEntryDetails")
@NotNull
private ChangeEntry changeEntry;
// constructor, getters and setters
}对于这些实体,下列测试(为演示目的)通过:
public class ChangeEntryTest {
private static EntityManagerFactory emf;
private EntityManager em;
@BeforeClass
public static void createEntityManagerFactory() {
emf = Persistence.createEntityManagerFactory("TestPu");
}
@AfterClass
public static void closeEntityManagerFactory() {
emf.close();
}
@Before
public void beginTransaction() {
em = emf.createEntityManager();
em.getTransaction().begin();
}
@After
public void rollbackTransaction() {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
if (em.isOpen()) {
em.close();
}
}
@Test
public void testCreateEntryWithoutDetails() {
try {
ChangeEntry entry = new ChangeEntry();
em.persist(entry);
fail("Expected ConstraintViolationException wasn't thrown.");
} catch (ConstraintViolationException e) {
assertEquals(1, e.getConstraintViolations().size());
ConstraintViolation<?> violation = e.getConstraintViolations()
.iterator().next();
assertEquals("changeEntryDetails", violation.getPropertyPath()
.toString());
assertEquals(NotNull.class, violation.getConstraintDescriptor()
.getAnnotation().annotationType());
}
}
@Test
public void testCreateDetailsWithoutEntry() {
try {
ChangeEntryDetails details = new ChangeEntryDetails();
em.persist(details);
fail("Expected ConstraintViolationException wasn't thrown.");
} catch (ConstraintViolationException e) {
assertEquals(1, e.getConstraintViolations().size());
ConstraintViolation<?> violation = e.getConstraintViolations()
.iterator().next();
assertEquals("changeEntry", violation.getPropertyPath()
.toString());
assertEquals(NotNull.class, violation.getConstraintDescriptor()
.getAnnotation().annotationType());
}
}
@Test
public void validEntryWithDetails() {
ChangeEntry entry = new ChangeEntry();
ChangeEntryDetails details = new ChangeEntryDetails();
entry.addDetails(details);
em.persist(entry);
Query query = em.createNamedQuery(ChangeEntry.FIND_ALL_CHANGEENTRIES);
assertEquals(1, query.getResultList().size());
}
}发布于 2010-04-27 21:05:55
因为您的级联类型,所以它应该持久化瞬态值。
如果在设置另一个瞬态元素之前,您实际上正在尝试持久化第一个元素,那么您将预期会出现此错误。
您指定的约束仅指定数据库中的值不能为空,而不是在数据模型中,显然,当您构造对象的新实例时,引用将为空。当引用为null时,不能持久化该实体。
发布于 2011-06-15 12:38:57
如果您在这里遇到了与 openJPA 和Pascals解决方案相同的问题,那么您可能需要在persistence.xml中将openJPA属性openjpa.InverseManager设置为true。
https://stackoverflow.com/questions/2725111
复制相似问题