Java 使用JPA在数据库中创建唯一行并合并现有行
我有两个表:Java 使用JPA在数据库中创建唯一行并合并现有行,java,jpa,orm,persistence,Java,Jpa,Orm,Persistence,我有两个表:User和Loan。 User有3个字段:id(主键),名字和姓氏贷款表中的字段用户id是用户表的外键: 通过持久化一个新的贷款我需要创建一个新的用户,如果他的名字和姓氏是唯一的,否则将他的id放在用户id中 loan.setSum(sum); loan.setUser(new User(firstName, lastName)); loanService.save(loan); 我的贷款类别的源代码: public class Loan { @Id @G
User
和Loan
。
User
有3个字段:id
(主键),名字和姓氏<代码>贷款
表中的字段用户id
是用户
表的外键:
通过持久化一个新的贷款
我需要创建一个新的用户
,如果他的名字
和姓氏
是唯一的,否则将他的id
放在用户id
中
loan.setSum(sum);
loan.setUser(new User(firstName, lastName));
loanService.save(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 ...
我正在使用此方法持久化新的用户
:
@PersistenceContext
private EntityManager em;
public void save(User user) {
if (user.getId() == null) {
em.persist(user);
} else {
em.merge(user);
}
}
当我试图保存一个新的贷款
时,它总是会保存一个新的用户
,该用户具有相同的名字
和姓氏
,但不同的id
loan.setSum(sum);
loan.setUser(new User(firstName, lastName));
loanService.save(loan);
要使用用户的名字
和姓氏
作为PK不是解决方案,我需要一个id
loan.setSum(sum);
loan.setUser(new User(firstName, lastName));
loanService.save(loan);
更新_1
我试图通过他的名字找到用户
:
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();
}
当我输入existinguser时,它会添加一个新用户,该用户具有相同的firstName
和lastName
,但具有新的id
。
重复此操作时,我遇到另一个异常:
javax.faces.FacesException: #{loanBean.requestLoan()}: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
javax.servlet.ServletException: javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
更新_2
非常感谢Pietro Boido提出的非常有用的建议。我在DB中的名字
和姓氏
字段上创建了唯一索引,并重构了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;
}
以下是一个可能的工作示例:
@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;
}
}
@无状态
公共类LoanService实现LoanServiceRemote{
@持久上下文
私人实体管理者;
@凌驾
公共用户createUser(用户用户){
em.persist(用户);
返回用户;
}
@凌驾
公共贷款(贷款){
em.persist(贷款);
System.out.println(“贷款持续:id=“+loan.getId());
归还贷款;
}
@凌驾
公共贷款储蓄贷款(贷款){
em.merge(贷款);
归还贷款;
}
@凌驾
公共长期递增贷款(整数贷款,长期金额){
Loan Loan=em.find(Loan.class,loanId);
如果(贷款!=null){
long sum=贷款。getSum()+金额;
/*
*实体已绑定到实体管理器,
*因为它是由find方法返回的。
*我们可以简单地设置它的属性和
*实体管理器将更新数据源
*在方法返回并提交事务之后。
*无需调用persist或merge。
*/
贷款总额;
回报金额;
}
返回null;
}
@凌驾
公共贷款(整数贷款){
Loan Loan=em.find(Loan.class,loanId);
如果(贷款!=null){
移除(贷款);
返回true;
}
返回false;
}
@凌驾
公共贷款融资(整型贷款){
返回em.find(Loan.class,loanId);
}
@凌驾
公共列表请求贷款(LoanRequest LoanRequest){
用户;
TypedQuery query=em.createQuery(“从user-user中选择user,其中user.firstName=:firstName和user.lastName=:lastName”,user.class);
query.setParameter(“firstName”,loanRequest.getFirstName());
query.setParameter(“lastName”,loanRequest.getLastName());
List users=query.getResultList();
if(users.isEmpty()){
user=新用户();
user.setFirstName(loanRequest.getFirstName());
user.setLastName(loanRequest.getLastName());
//新实体必须持久化
em.persist(用户);
}否则{
user=users.get(0);
}
列出贷款=新建ArrayList();
Long[]totals=loanRequest.getTotals();
对于(int i=0;i
单元测试:
@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());
}
@测试
公共贷款{
User User=loanService.createUser(newUser());
Loan loan1=新贷款();
贷款1.固定资产(10升);
loan1.setUser(用户);
Loan loan2=loanService.createLoan(loan1);
资产不为空(贷款2);
整数loanId=loan2.getId();
资产不为空(loanId);
assertEquals(loan1.getSum(),loan2.getSum());
assertEquals(loan1.getUser(),user);
User user2=loanService.createUser(newUser());
loan2.setUser(user2);
贷款2.固定金额(20L);
Loan loan3=loanService.saveLoan(loan2);
资产贷款质量(贷款2、贷款3);
长期总额=贷款服务增量贷款(贷款额度,10L);
assertNotNull(总计);
资产质量((长期)(贷款3.getSum()+10L),总计);
贷款3.固定资产(总计);
Loan loan4=loanService.findLoan(loanId);
资产贷款质量(贷款3、贷款4);
布尔结果=loanService.deleteLoan(loanId);
资产真实性(结果);
Loan loan5=loanService.findLoan(loanId);
资产净值(贷款5);
长[]总计=新长[]{1L,2L,3L};
LoanRequest LoanRequest=新的LoanRequest();
loanRequest.setFirstName(“Amerigo”);
loanRequest.setLastName(“Vespucci”);
贷款请求。设置总计(总计);
列出贷款=loanService.requestLoans(loanRequest);
资产(贷款);
资产质量(3,loans.size());
对于(int i=0;i<3;i++){
assertEquals(总计[i],loans.get(i).getSum());
loanService.deleteLoan(loans.get(i).getId());
}
}
无效资产贷款资格(贷款1、贷款2){
资产负债表