为什么要在Spring Data JPA Repository上的save()之后使用返回的实例?

这里是代码:

@Repository public interface AccountRepository extends JpaRepository<Account, Long> {} 

来自Spring Data JPA项目的JpaRepository

这里是testing代码:

 public class JpaAccountRepositoryTest extends JpaRepositoryTest { @Inject private AccountRepository accountRepository; @Inject private Account account; @Test @Transactional public void createAccount() { Account returnedAccount = accountRepository.save(account); System.out.printf("account ID is %d and for returned account ID is %d\n", account.getId(), returnedAccount.getId()); } } 

结果如下:

 account ID is 0 and for returned account ID is 1 

这里是从CrudReporsitory.save()javadoc:

保存给定的实体。 使用返回的实例进行进一步操作,因为保存操作可能已经完全更改了实体实例。

这里是Spring Data JPA的SimpleJpaRepository的实际代码:

  @Transactional public T save(T entity) { if (entityInformation.isNew(entity)) { em.persist(entity); return entity; } else { return em.merge(entity); } } 

所以,问题是为什么我们需要使用返回的实例而不是原来的实例呢? (是的,我们必须这样做,否则我们继续与独立的实例合作,但为什么)

最初的EntityManager.persist()方法返回void,所以我们的实例被连接到持久化上下文。 在将帐户传递到存储库时是否发生了一些代理魔术? 是Spring Data JPA项目的架构限制吗?

CrudRepository接口的save(…)方法应该抽象地简单地存储一个实体,而不CrudRepository在什么状态。因此,它不能公开实际的存储特定的实现,即使(如在JPA中)商店区分要存储的新实体和现有的要更新的实体。 这就是为什么该方法实际上被称为save(…)而不是create(…)update(…) 。 我们从该方法返回一个结果,实际上允许商店实现返回一个完全不同的实例,就像JPA在调用merge(…)时潜在的那样。

所以一般来说,API的决定更多的是对实际的实现宽松,从而像我们一样执行JPA的方法。 对通过的实体没有额外的代理按摩。

您错过了第二部分:如果实体不是新的,则调用mergemerge其参数的状态复制到具有相同ID的附加实体中,并返回附加实体。 如果实体不是新的,并且不使用返回的实体,则将对分离的实体进行修改。