diff --git a/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/entity/Account.java b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/entity/Account.java new file mode 100644 index 0000000000..48a98512fa --- /dev/null +++ b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/entity/Account.java @@ -0,0 +1,43 @@ +package com.baeldung.jpa.entity; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.IdClass; + +@Entity +@IdClass(AccountId.class) +public class Account { + + @Id + private String accountNumber; + + @Id + private String accountType; + + private String description; + + public String getAccountNumber() { + return accountNumber; + } + + public void setAccountNumber(String accountNumber) { + this.accountNumber = accountNumber; + } + + public String getAccountType() { + return accountType; + } + + public void setAccountType(String accountType) { + this.accountType = accountType; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + +} diff --git a/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/entity/AccountId.java b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/entity/AccountId.java new file mode 100644 index 0000000000..091c326367 --- /dev/null +++ b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/entity/AccountId.java @@ -0,0 +1,52 @@ +package com.baeldung.jpa.entity; + +import java.io.Serializable; + +public class AccountId implements Serializable { + + private static final long serialVersionUID = 1L; + + private String accountNumber; + private String accountType; + + public AccountId() { + + } + + public AccountId(String accountNumber, String accountType) { + this.accountNumber = accountNumber; + this.accountType = accountType; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((accountNumber == null) ? 0 : accountNumber.hashCode()); + result = prime * result + ((accountType == null) ? 0 : accountType.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + AccountId other = (AccountId) obj; + if (accountNumber == null) { + if (other.accountNumber != null) + return false; + } else if (!accountNumber.equals(other.accountNumber)) + return false; + if (accountType == null) { + if (other.accountType != null) + return false; + } else if (!accountType.equals(other.accountType)) + return false; + return true; + } + +} diff --git a/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/entity/Book.java b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/entity/Book.java new file mode 100644 index 0000000000..460f302e28 --- /dev/null +++ b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/entity/Book.java @@ -0,0 +1,34 @@ +package com.baeldung.jpa.entity; + +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; + +@Entity +public class Book { + + @EmbeddedId + private BookId bookId; + + private String description; + + public Book() { + + } + + public Book(BookId bookId) { + this.bookId = bookId; + } + + public BookId getBookId() { + return bookId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + +} diff --git a/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/entity/BookId.java b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/entity/BookId.java new file mode 100644 index 0000000000..ff587beaf2 --- /dev/null +++ b/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/entity/BookId.java @@ -0,0 +1,62 @@ +package com.baeldung.jpa.entity; + +import java.io.Serializable; + +import javax.persistence.Embeddable; + +@Embeddable +public class BookId implements Serializable { + + private static final long serialVersionUID = 1L; + private String title; + private String language; + + public BookId() { + + } + + public BookId(String title, String language) { + this.title = title; + this.language = language; + } + + public String getTitle() { + return title; + } + + public String getLanguage() { + return language; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((language == null) ? 0 : language.hashCode()); + result = prime * result + ((title == null) ? 0 : title.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + BookId other = (BookId) obj; + if (language == null) { + if (other.language != null) + return false; + } else if (!language.equals(other.language)) + return false; + if (title == null) { + if (other.title != null) + return false; + } else if (!title.equals(other.title)) + return false; + return true; + } + +} diff --git a/persistence-modules/java-jpa/src/main/resources/META-INF/persistence.xml b/persistence-modules/java-jpa/src/main/resources/META-INF/persistence.xml index 298397e39d..fc3ff05255 100644 --- a/persistence-modules/java-jpa/src/main/resources/META-INF/persistence.xml +++ b/persistence-modules/java-jpa/src/main/resources/META-INF/persistence.xml @@ -1,183 +1,226 @@ + version="2.2"> - - org.hibernate.jpa.HibernatePersistenceProvider - com.baeldung.sqlresultsetmapping.ScheduledDay - com.baeldung.sqlresultsetmapping.Employee - true - - - - - - - - - - - + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.sqlresultsetmapping.ScheduledDay + com.baeldung.sqlresultsetmapping.Employee + true + + + + + + + + + + + - - org.hibernate.jpa.HibernatePersistenceProvider - com.baeldung.jpa.stringcast.Message - com.baeldung.jpa.enums.Article - com.baeldung.jpa.enums.CategoryConverter - true - - - - - - - - - - - + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.stringcast.Message + com.baeldung.jpa.enums.Article + com.baeldung.jpa.enums.CategoryConverter + true + + + + + + + + + + + - - org.hibernate.jpa.HibernatePersistenceProvider - com.baeldung.jpa.model.Car - true - - - - - - - - - + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.model.Car + true + + + + + + + + + - - com.baeldung.jpa.entitygraph.model.Post - com.baeldung.jpa.entitygraph.model.User - com.baeldung.jpa.entitygraph.model.Comment - true - + + com.baeldung.jpa.entitygraph.model.Post + com.baeldung.jpa.entitygraph.model.User + com.baeldung.jpa.entitygraph.model.Comment + true + - - - + + + - - - - + + + + - - org.eclipse.persistence.jpa.PersistenceProvider - com.baeldung.jpa.datetime.JPA22DateTimeEntity - true - - - - - - + + org.eclipse.persistence.jpa.PersistenceProvider + com.baeldung.jpa.datetime.JPA22DateTimeEntity + true + + + + + + - - - - - - + + + + + + - - org.hibernate.jpa.HibernatePersistenceProvider - com.baeldung.jpa.criteria.entity.Item - true - - - - - - - - - - - - + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.criteria.entity.Item + true + + + + + + + + + + + + - - org.hibernate.jpa.HibernatePersistenceProvider - com.baeldung.jpa.querytypes.UserEntity - true - - - - - - - - - - - - + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.querytypes.UserEntity + true + + + + + + + + + + + + - - org.hibernate.jpa.HibernatePersistenceProvider - com.baeldung.jpa.defaultvalues.User - true - - - - - - - - - - - - - - org.hibernate.jpa.HibernatePersistenceProvider - com.baeldung.jpa.entity.Student - true - - - - - - - - - - - + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.defaultvalues.User + true + + + + + + + + + + + - - org.hibernate.jpa.HibernatePersistenceProvider - com.baeldung.jpa.projections.Product - true - - - - - - - - - - - - + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.entity.Student + com.baeldung.jpa.entity.Book + com.baeldung.jpa.entity.BookId + com.baeldung.jpa.entity.Account + com.baeldung.jpa.entity.AccountId + true + + + + + + + + + + + + + + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.jpa.projections.Product + true + + + + + + + + + + + + \ No newline at end of file diff --git a/persistence-modules/java-jpa/src/test/java/com/baeldung/jpa/entity/CompositeKeysIntegrationTest.java b/persistence-modules/java-jpa/src/test/java/com/baeldung/jpa/entity/CompositeKeysIntegrationTest.java new file mode 100644 index 0000000000..2d30ebab5e --- /dev/null +++ b/persistence-modules/java-jpa/src/test/java/com/baeldung/jpa/entity/CompositeKeysIntegrationTest.java @@ -0,0 +1,114 @@ +package com.baeldung.jpa.entity; + +import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class CompositeKeysIntegrationTest { + + private static final String SAVINGS_ACCOUNT = "Savings"; + private static final String ACCOUNT_NUMBER = "JXSDF324234"; + private static final String ENGLISH = "English"; + private static final String WAR_AND_PEACE = "War and Peace"; + + private static EntityManagerFactory emf; + private static EntityManager em; + + @BeforeClass + public static void setup() { + emf = Persistence.createEntityManagerFactory("jpa-entity-definition"); + em = emf.createEntityManager(); + } + + @Test + public void persistBookWithCompositeKeyThenRetrieveDetails() { + Book warAndPeace = createBook(); + persist(warAndPeace); + clearThePersistenceContext(); + Book book = findBookByBookId(); + verifyAssertionsWith(book); + } + + @Test + public void persistAccountWithCompositeKeyThenRetrieveDetails() { + Account savingsAccount = createAccount(); + persist(savingsAccount); + clearThePersistenceContext(); + Account account = findAccountByAccountId(); + verifyAssertionsWith(account); + } + + @AfterClass + public static void destroy() { + if (em != null) { + em.close(); + } + if (emf != null) { + emf.close(); + } + } + + private Account createAccount() { + Account savingsAccount = new Account(); + savingsAccount.setAccountNumber(ACCOUNT_NUMBER); + savingsAccount.setAccountType(SAVINGS_ACCOUNT); + savingsAccount.setDescription("Savings account"); + return savingsAccount; + } + + private void verifyAssertionsWith(Account account) { + assertEquals(ACCOUNT_NUMBER, account.getAccountNumber()); + assertEquals(SAVINGS_ACCOUNT, account.getAccountType()); + } + + private Account findAccountByAccountId() { + return em.find(Account.class, new AccountId(ACCOUNT_NUMBER, SAVINGS_ACCOUNT)); + } + + private void persist(Account account) { + em.getTransaction() + .begin(); + em.persist(account); + em.getTransaction() + .commit(); + } + + private Book findBookByBookId() { + return em.find(Book.class, new BookId(WAR_AND_PEACE, ENGLISH)); + } + + private Book createBook() { + BookId bookId = new BookId(WAR_AND_PEACE, ENGLISH); + Book warAndPeace = new Book(bookId); + warAndPeace.setDescription("Novel and Historical Fiction"); + return warAndPeace; + } + + private void verifyAssertionsWith(Book book) { + assertNotNull(book); + assertNotNull(book.getBookId()); + assertEquals(WAR_AND_PEACE, book.getBookId() + .getTitle()); + assertEquals(ENGLISH, book.getBookId() + .getLanguage()); + } + + private void persist(Book book) { + em.getTransaction() + .begin(); + em.persist(book); + em.getTransaction() + .commit(); + } + + private void clearThePersistenceContext() { + em.clear(); + } +}