JavaPersistenceWithHibernate第二版笔记-第六章-Mapping inheritance-008Polymorphic many-to-one associations(@ManyToOne、@Inheritance、)
一、结构
二、代码
1.
1 package org.jpwh.model.inheritance.associations.manytoone; 2 3 import org.jpwh.model.Constants; 4 5 import javax.persistence.*; 6 import javax.validation.constraints.NotNull; 7 8 // Can not be @MappedSuperclass when it's a target class in associations! 9 @Entity 10 @Inheritance(strategy = InheritanceType.JOINED) 11 public abstract class BillingDetails { 12 13 protected Long id; 14 15 @NotNull 16 protected String owner; 17 18 protected BillingDetails() { 19 } 20 21 protected BillingDetails(String owner) { 22 this.owner = owner; 23 } 24 25 // Use property instead of field access, so calling getId() doesn't initialize a proxy! 26 @Id 27 @GeneratedValue(generator = Constants.ID_GENERATOR) 28 public Long getId() { 29 return id; 30 } 31 32 private void setId(Long id) { 33 this.id = id; 34 } 35 36 public String getOwner() { 37 return owner; 38 } 39 40 public void setOwner(String owner) { 41 this.owner = owner; 42 } 43 44 public void pay(int amount) { 45 // NOOP 46 } 47 }
2.
1 package org.jpwh.model.inheritance.associations.manytoone; 2 3 import javax.persistence.Entity; 4 import javax.validation.constraints.NotNull; 5 6 @Entity 7 public class CreditCard extends BillingDetails { 8 9 @NotNull 10 protected String cardNumber; 11 12 @NotNull 13 protected String expMonth; 14 15 @NotNull 16 protected String expYear; 17 18 public CreditCard() { 19 super(); 20 } 21 22 public CreditCard(String owner, String cardNumber, String expMonth, String expYear) { 23 super(owner); 24 this.cardNumber = cardNumber; 25 this.expMonth = expMonth; 26 this.expYear = expYear; 27 } 28 29 public String getCardNumber() { 30 return cardNumber; 31 } 32 33 public void setCardNumber(String cardNumber) { 34 this.cardNumber = cardNumber; 35 } 36 37 public String getExpMonth() { 38 return expMonth; 39 } 40 41 public void setExpMonth(String expMonth) { 42 this.expMonth = expMonth; 43 } 44 45 public String getExpYear() { 46 return expYear; 47 } 48 49 public void setExpYear(String expYear) { 50 this.expYear = expYear; 51 } 52 53 }
3.
1 package org.jpwh.model.inheritance.associations.manytoone; 2 3 import javax.persistence.Entity; 4 import javax.validation.constraints.NotNull; 5 6 @Entity 7 public class BankAccount extends BillingDetails { 8 9 @NotNull 10 protected String account; 11 12 @NotNull 13 protected String bankname; 14 15 @NotNull 16 protected String swift; 17 18 public BankAccount() { 19 super(); 20 } 21 22 public BankAccount(String owner, String account, String bankname, String swift) { 23 super(owner); 24 this.account = account; 25 this.bankname = bankname; 26 this.swift = swift; 27 } 28 29 public String getAccount() { 30 return account; 31 } 32 33 public void setAccount(String account) { 34 this.account = account; 35 } 36 37 public String getBankname() { 38 return bankname; 39 } 40 41 public void setBankname(String bankname) { 42 this.bankname = bankname; 43 } 44 45 public String getSwift() { 46 return swift; 47 } 48 49 public void setSwift(String swift) { 50 this.swift = swift; 51 } 52 }
4.
1 package org.jpwh.model.inheritance.associations.manytoone; 2 3 import org.jpwh.model.Constants; 4 5 import javax.persistence.*; 6 import javax.validation.constraints.NotNull; 7 8 @Entity 9 @Table(name = "USERS") 10 public class User { 11 12 @Id 13 @GeneratedValue(generator = Constants.ID_GENERATOR) 14 protected Long id; 15 16 @NotNull 17 protected String username; 18 19 @ManyToOne(fetch = FetchType.LAZY) 20 protected BillingDetails defaultBilling; 21 22 public User() { 23 } 24 25 public User(String username) { 26 this.username = username; 27 } 28 29 public Long getId() { 30 return id; 31 } 32 33 public String getUsername() { 34 return username; 35 } 36 37 public void setUsername(String username) { 38 this.username = username; 39 } 40 41 public BillingDetails getDefaultBilling() { 42 return defaultBilling; 43 } 44 45 public void setDefaultBilling(BillingDetails defaultBilling) { 46 this.defaultBilling = defaultBilling; 47 } 48 49 50 // ... 51 }
5.测试
1 package org.jpwh.test.inheritance; 2 3 4 import org.jpwh.env.JPATest; 5 import org.jpwh.model.inheritance.associations.manytoone.BillingDetails; 6 import org.jpwh.model.inheritance.associations.manytoone.CreditCard; 7 import org.jpwh.model.inheritance.associations.manytoone.User; 8 import org.testng.annotations.BeforeClass; 9 import org.testng.annotations.Test; 10 11 import javax.persistence.EntityManager; 12 import javax.transaction.UserTransaction; 13 14 import static org.testng.Assert.*; 15 16 public class PolymorphicManyToOne extends JPATest { 17 18 @Override 19 public void configurePersistenceUnit() throws Exception { 20 configurePersistenceUnit("PolymorphicManyToOnePU"); 21 } 22 23 @Test 24 public void storeAndLoadItemBids() throws Exception { 25 UserTransaction tx = TM.getUserTransaction(); 26 try { 27 tx.begin(); 28 EntityManager em = JPA.createEntityManager(); 29 30 CreditCard cc = new CreditCard( 31 "John Doe", "1234123412341234", "06", "2015" 32 ); 33 User johndoe = new User("johndoe"); 34 johndoe.setDefaultBilling(cc); 35 36 em.persist(cc); 37 em.persist(johndoe); 38 39 tx.commit(); 40 em.close(); 41 42 Long USER_ID = johndoe.getId(); 43 44 tx.begin(); 45 em = JPA.createEntityManager(); 46 { 47 User user = em.find(User.class, USER_ID); 48 49 // Invoke the pay() method on a concrete subclass of BillingDetails 50 user.getDefaultBilling().pay(123); 51 assertEquals(user.getDefaultBilling().getOwner(), "John Doe"); 52 } 53 54 tx.commit(); 55 em.close(); 56 57 tx.begin(); 58 em = JPA.createEntityManager(); 59 { 60 User user = em.find(User.class, USER_ID); 61 62 BillingDetails bd = user.getDefaultBilling(); 63 64 assertFalse(bd instanceof CreditCard); 65 66 // Don't do this, ClassCastException! 67 // CreditCard creditCard = (CreditCard) bd; 68 } 69 { 70 User user = em.find(User.class, USER_ID); 71 72 //because the defaultBilling property is 73 // mapped with FetchType.LAZY , Hibernate will proxy the association target. 74 BillingDetails bd = user.getDefaultBilling(); 75 76 CreditCard creditCard = 77 em.getReference(CreditCard.class, bd.getId()); // No SELECT! 78 79 assertTrue(bd != creditCard); // Careful! 80 } 81 tx.commit(); 82 em.close(); 83 84 tx.begin(); 85 em = JPA.createEntityManager(); 86 { 87 User user = (User) em.createQuery( 88 "select u from User u " + 89 "left join fetch u.defaultBilling " + 90 "where u.id = :id") 91 .setParameter("id", USER_ID) 92 .getSingleResult(); 93 94 // No proxy has been used, the BillingDetails instance has been fetched eagerly 95 CreditCard creditCard = (CreditCard) user.getDefaultBilling(); 96 } 97 tx.commit(); 98 em.close(); 99 100 } finally { 101 TM.rollback(); 102 } 103 } 104 105 }
You can do anything you set your mind to, man!