Announcement Announcement Module
Collapse
No announcement yet.
Simple unidirectional @OneToOne Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Simple unidirectional @OneToOne

    Hi,

    I found this simple example, but I'm surprised there is no easy solution as I would think this was a common user case. (Using Spring 3.2, Hibernate 4.2.1 and Mysql).

    http://fruzenshtein.com/one-to-one-u...l-primary-key/

    I wanted to avoid calling persist, so I tried various solutions (@PrimaryKeyJoinColumn, bidirectional, etc.) but I could not find a way to get this to work.

    I assume the problem is that that Author needs to be persisted first to get the auto-generated Id, but I thought that Hibernate would handle this.

    I was trying to find an elegant way to use this via a repository. If calling "persist" is the only solution, where/how do I add this in a repository.
    Code:
    session.persist(author);
    Code:
    @Repository
    public interface AuthorRepository
            extends JpaSpecificationExecutor<Author>,
            JpaRepository<Author, Integer> {}
    Any hints appreciated...

    Just to clarify:
    I want to be able to call repository.save(author) and have everything persisted. I want to avoid have to persist the author, get the id, set the id, and then save().
    Last edited by alforbes; May 13th, 2013, 12:26 PM.

  • #2
    Originally posted by alforbes View Post
    Hi,
    ...
    I want to be able to call repository.save(author) and have everything persisted. I want to avoid have to persist the author, get the id, set the id, and then save().
    As far as I can tell, because of the way the Biography class (and underlying database table) are designed in the article you mentioned, it's necessary to follow that set of steps. The id (primary key) for Biography is defined as one which must be set by the application. Until the Author object is saved, it doesn't have an ID, and the Biography instance needs that ID value for its primary key. Perhaps Hibernate should be able to figure this out, but it doesn't.

    I might be wrong, but I think its better to design a table so that its primary key does not have "business meaning". In your case, the "author ID" has business meaning, i.e., the relationship identifier. I would add a regular integer primary key to the Biography table, and define the relationship between Biography and Author in terms of the objects themselves, not by IDs. That is, write biography.setAuthor(anAuthor) instead of biography.setAuthorId(anAuthorId).

    Author:
    Code:
    @Entity
    @Table(name="authors")
    public class Author extends AbstractPersistable<Long> implements Serializable {
    
    	private String name;
    
    	@OneToOne(cascade=CascadeType.ALL)  
    	@PrimaryKeyJoinColumn(name="id", referencedColumnName="author_id")
    	private Biography biography; 
    
    	public Author() {}
    
    	public String getName() {
    		return this.name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public Biography getBiography() {
    		return this.biography;
    	}
    
    	public void setBiography(Biography biography) {
    		this.biography = biography;
    	}
    
    }
    Biography:
    Code:
    @Entity
    @Table(name = "biographies")
    public class Biography extends AbstractPersistable<Long> implements Serializable {
    
        private String information;
    
        // bi-directional one-to-one association to Author
        @OneToOne
        private Author author;
    
        public Biography() { }
    
        public String getInformation() {
            return this.information;
        }
    
        public void setInformation(String information) {
            this.information = information;
        }
    
        public Author getAuthor() {
            return this.author;
        }
    
        public void setAuthor(Author author) {
            this.author = author;
        }
    
    }
    For MySQL, the createDDL.sql would read:
    Code:
    CREATE TABLE authors (ID BIGINT NOT NULL AUTO_INCREMENT, NAME VARCHAR(255), PRIMARY KEY (ID));
    CREATE TABLE biographies (ID BIGINT NOT NULL AUTO_INCREMENT, INFORMATION VARCHAR(255), AUTHOR_ID BIGINT, PRIMARY KEY (ID));
    ALTER TABLE authors ADD CONSTRAINT FK_authors_ID FOREIGN KEY (ID) REFERENCES biographies (AUTHOR_ID);
    ALTER TABLE biographies ADD CONSTRAINT FK_biographies_AUTHOR_ID FOREIGN KEY (AUTHOR_ID) REFERENCES authors (ID);
    Using the repository you showed, here's a unit test:
    Code:
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = { "classpath:/application-context.xml" })
    @Transactional
    public class AuthorRepositoryTest {
    
        private static final Logger log = LoggerFactory.getLogger(AuthorRepositoryTest.class);
    
        @Autowired
        private AuthorRepository repository;
    
        private ClassPathXmlApplicationContext ctx;
        
        /**
         * @throws java.lang.Exception
         */
        @Before
        public void setUp() throws Exception {
           ctx = new ClassPathXmlApplicationContext();
        }
    
        @Test
        public void testSavingAuthor() {
            Author author = new Author();
            author.setName("Thomas Wolfe");
    
            Biography biography = new Biography();
            biography.setInformation("Wolfe was an American author...");
            biography.setAuthor(author);
    
            author.setBiography(biography);
    
            repository.save(author);
    
            List<Author> list = repository.findAll();
            log.debug("list of authors: {}", list);
            // add an "assert...()" statement or two here to actually perform a test
       }
    }
    Note that I commented out the @Transactional declaration at the top of the repository test class. Comment it out if you actually want to see the results in the database, assuming you are not using an in-memory db which disappears when the test finishes.

    Comment

    Working...
    X