休眠@OneToOne @NotNull [英] Hibernate @OneToOne @NotNull
问题描述
在关系的两边声明@OneToOne
和@NotNull
是否有效,例如:
Is it valid to declare @OneToOne
and @NotNull
on both sides of a relationship, such as:
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会暂时为空)
I can't find anything that says this is invalid, but it seems that during persistence at least one side of the relationship must be violated. (Eg., if writing changeEntry first, changeEntryDetails will be null temporarily).
尝试此操作时,我看到抛出异常not-null 属性引用空值或瞬态值
.
When trying this, I see an exception thrown not-null property references a null or transient value
.
如果可能,我想避免放松约束,因为双方必须都在场.
I'd like to avoid relaxing the constraint if possible, because both sides must be present.
推荐答案
在关系的双方声明
@OneToOne
和@NotNull
是否有效 (...) 我找不到任何说明这是无效的,但似乎在坚持期间,至少必须违反关系的一侧.(比如先写changeEntry
,changeEntryDetails
会暂时为null).
Is it valid to declare
@OneToOne
and@NotNull
on both sides of a relationship (...) I can't find anything that says this is invalid, but it seems that during persistence at least one side of the relationship must be violated. (e.g. if writingchangeEntry
first,changeEntryDetails
will be null temporarily).
它是有效的,并且在正确映射实体的情况下一切正常.您需要将双向关联的一侧声明为拥有"侧(此控制"插入顺序).一种可能的工作解决方案:
It is valid and everything works fine with properly mapped entities. You need to declare one side of your bi-directional association as the "owning" side (this "control" the order of inserts). One possible working solution:
@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
属性设置在关联的非拥有方):
And for the other entity (note the mappedBy
attribute set on the non-owning side of the association):
@Entity
public class ChangeEntryDetails implements Serializable {
@Id
@GeneratedValue
private Long id;
@OneToOne(optional = false, mappedBy = "changeEntryDetails")
@NotNull
private ChangeEntry changeEntry;
// constructor, getters and setters
}
对于这些实体,以下测试(用于演示目的)通过:
With these entities, the following test (for demonstration purposes) passes:
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());
}
}
这篇关于休眠@OneToOne @NotNull的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!