[英]Creating a JPA Entity from a Map<String,String> representing a database row
[英]Creating unique and merging existing row in database with JPA
我有2個表: User
和Loan
。 User
具有3個字段: id
(PK), first_name
和last_name
。 Loan
表的字段user_id
是User
表的外鍵:
如果他的first_name
和last_name
是唯一的,則通過保留新的Loan
我需要創建一個新的User
,否則將其id
放在uder_id
。
我的Loan類的源代碼:
public class Loan {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Long sum;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "user_id")
private User user;
... methods ...
我正在使用這種方法來保留新User
:
@PersistenceContext
private EntityManager em;
public void save(User user) {
if (user.getId() == null) {
em.persist(user);
} else {
em.merge(user);
}
}
當我嘗試保存新的Loan
它總是以first_name
和last_name
相同但id
不同的方式持久保存一個新User
。
loan.setSum(sum);
loan.setUser(new User(firstName, lastName));
loanService.save(loan);
要使用用戶的first_name
和last_name
作為PK不是解決方案,我需要一個id
。
UPDATE_1
我試圖通過User
名查找User
:
public User findByName(String firstName, String lastName) {
TypedQuery<User> query = em.createQuery(
"SELECT u FROM User u WHERE u.firstName = :firstName " +
"AND u.lastName = :lastName", User.class)
.setParameter("firstName", firstName).setParameter("lastName", lastName);
return query.getSingleResult();
}
但是當我輸入新用戶時,我得到了一個例外:
javax.faces.FacesException: #{loanBean.requestLoan()}: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
當我輸入現有用戶時,它將添加一個具有相同firstName
和lastName
但具有新id
新用戶。 當我重復此操作時,我得到另一個異常:
javax.servlet.ServletException: javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
UPDATE_2非常感謝Pietro Boido的寶貴建議。我在DB的first_name
和last_name
字段上創建了唯一索引,並重構了save()
方法。 但是現在當我輸入現有用戶的數據時,我得到了新的例外
javax.servlet.ServletException: org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'FIRST_LAST_NAME' defined on 'USER'.
Error Code: 20000
您應該首先執行查詢以按名稱查找用戶,並僅在未找到用戶時創建一個新用戶:
User user = userService.find(firstName, lastName);
if (user == null) {
user = loanService.createUser(new User(firstName, lastName));
}
loan.setSum(sum);
loan.setUser(user);
loanService.save(loan);
由於可能沒有給定名稱的用戶,因此在查詢用戶時請使用getResultList,因為getSingleResult希望始終找到結果。
List<User> users = query.getResultList();
if (!users.isEmpty()) {
return users.iterator().next();
} else {
return null;
}
該代碼假定數據庫在first_name,last_name上具有唯一索引。
您不應該對ManyToOne關系進行級聯操作。 考慮一下:如果您刪除貸款,是否也應該刪除用戶?
當關聯實體是關聯實體的一部分並且它們的生命周期被一起管理時,應該使用級聯操作。
@Entity
@Table(name="loans")
public class Loan implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "total")
private Long sum;
@ManyToOne()
@JoinColumn(name = "user_id")
private User user;
//...
}
這是一個可能的工作示例:
@Stateless
public class LoanService implements LoanServiceRemote {
@PersistenceContext
private EntityManager em;
@Override
public User createUser(User user) {
em.persist(user);
return user;
}
@Override
public Loan createLoan(Loan loan) {
em.persist(loan);
System.out.println("loan persisted: id=" + loan.getId());
return loan;
}
@Override
public Loan saveLoan(Loan loan) {
em.merge(loan);
return loan;
}
@Override
public Long incrementLoan(Integer loanId, long amount) {
Loan loan = em.find(Loan.class, loanId);
if (loan != null) {
long sum = loan.getSum() + amount;
/*
* The entity is bound to the entity manager,
* because it was returned by the find method.
* We can simply set its properties and
* the entity manager will update the datasource
* after the method returns and the transaction commits.
* No need to call persist or merge.
*/
loan.setSum(sum);
return sum;
}
return null;
}
@Override
public boolean deleteLoan(Integer loanId) {
Loan loan = em.find(Loan.class, loanId);
if (loan != null) {
em.remove(loan);
return true;
}
return false;
}
@Override
public Loan findLoan(Integer loanId) {
return em.find(Loan.class, loanId);
}
@Override
public List<Loan> requestLoans(LoanRequest loanRequest) {
User user;
TypedQuery<User> query = em.createQuery("select user from User user where user.firstName = :firstName and user.lastName = :lastName", User.class);
query.setParameter("firstName", loanRequest.getFirstName());
query.setParameter("lastName", loanRequest.getLastName());
List<User> users = query.getResultList();
if (users.isEmpty()) {
user = new User();
user.setFirstName(loanRequest.getFirstName());
user.setLastName(loanRequest.getLastName());
//new entities must be persisted
em.persist(user);
} else {
user = users.get(0);
}
List<Loan> loans = new ArrayList<>();
Long[] totals = loanRequest.getTotals();
for (int i = 0; i < totals.length; i++) {
Loan loan = new Loan();
loan.setSum(totals[i]);
loan.setUser(user);
em.persist(loan);
loans.add(loan);
}
return loans;
}
}
單元測試:
@Test
public void testLoan() {
User user = loanService.createUser(newUser());
Loan loan1 = new Loan();
loan1.setSum(10L);
loan1.setUser(user);
Loan loan2 = loanService.createLoan(loan1);
assertNotNull(loan2);
Integer loanId = loan2.getId();
assertNotNull(loanId);
assertEquals(loan1.getSum(), loan2.getSum());
assertEquals(loan1.getUser(), user);
User user2 = loanService.createUser(newUser());
loan2.setUser(user2);
loan2.setSum(20L);
Loan loan3 = loanService.saveLoan(loan2);
assertLoanEquals(loan2, loan3);
Long total = loanService.incrementLoan(loanId, 10L);
assertNotNull(total);
assertEquals((Long)(loan3.getSum() + 10L), total);
loan3.setSum(total);
Loan loan4 = loanService.findLoan(loanId);
assertLoanEquals(loan3, loan4);
boolean result = loanService.deleteLoan(loanId);
assertTrue(result);
Loan loan5 = loanService.findLoan(loanId);
assertNull(loan5);
Long[] totals = new Long[]{1L,2L,3L};
LoanRequest loanRequest = new LoanRequest();
loanRequest.setFirstName("Amerigo");
loanRequest.setLastName("Vespucci");
loanRequest.setTotals(totals);
List<Loan> loans = loanService.requestLoans(loanRequest);
assertNotNull(loans);
assertEquals(3, loans.size());
for (int i = 0; i < 3; i++) {
assertEquals(totals[i], loans.get(i).getSum());
loanService.deleteLoan(loans.get(i).getId());
}
}
void assertLoanEquals(Loan loan1, Loan loan2) {
assertNotNull(loan1);
assertNotNull(loan2);
assertEquals(loan1.getSum(), loan2.getSum());
assertUserEquals(loan1.getUser(), loan2.getUser());
assertEquals(loan1.getId(), loan2.getId());
}
void assertUserEquals(User user, User user2) {
assertNotNull(user);
assertNotNull(user2);
assertEquals(user.getId(), user2.getId());
assertEquals(user.getFirstName(), user2.getFirstName());
assertEquals(user.getLastName(), user2.getLastName());
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.