Hibernate @OneToOne @NotNull

后端 未结 3 1985
离开以前
离开以前 2020-12-15 08:33

Is it valid to declare @OneToOne and @NotNull on both sides of a relationship, such as:

class ChangeEntry
{
    @OneToOne(cascade=C         


        
3条回答
  •  [愿得一人]
    2020-12-15 08:56

    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 writing changeEntry 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
    }
    

    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());
        }
    }
    

提交回复
热议问题