source 는 Github 에 있습니다.
SimpleJpaRepository.java
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#save(java.lang.Object)
*/
@Transactional
@Override
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
The following table describes the strategies that Spring Data offers for detecting whether an entity is new:
@Id -Property inspection (the default) | By default, Spring Data inspects the version property of the given entity. If the identifier property is null or 0 in case of primitive types, then the entity is assumed to be new. Otherwise, it is assumed to not be new. |
---|---|
@Version -Property inspection | If a property annotated with @Version is present and null , or in case of a version property of primitive type 0 the entity is considered new. If the version property is present but has a different value, the entity is considered to not be new. If no version property is present Spring Data falls back to inspection of the Id-Property. |
Implementing Persistable | If an entity implements Persistable , Spring Data delegates the new detection to the isNew(…) method of the entity. See the Javadoc for details.Note: Properties of Persistable will get detected and persisted if you use AccessType.PROPERTY . To avoid that, use @Transient . |
Providing a custom EntityInformation implementation | You can customize the EntityInformation abstraction used in the repository base implementation by creating a subclass of the module specific repository factory and overriding the getEntityInformation(…) method. You then have to register the custom implementation of module specific repository factory as a Spring bean. Note that this should rarely be necessary. |
@Test
public void ID식별자_ISNEW_테스트() throws Exception {
EntityInformation<IsNewSampleWithPrimitiveId, Long> entityInformation =
new JpaMetamodelEntityInformation<>(IsNewSampleWithPrimitiveId.class, entityManager.getMetamodel());
IsNewSampleWithPrimitiveId sample = new IsNewSampleWithPrimitiveId();
// 아무 것도 세팅 안했으니 isNew -> true
Assert.assertThat(entityInformation.isNew(sample), is(true));
// @Id 에 값이 존재하니 new 가 아님.
sample.setId(1L);
Assert.assertThat(entityInformation.isNew(sample), is(false));
// @Id 에 다시 null 을 넣으면 newState 상태
sample.setId(null);
Assert.assertThat(entityInformation.isNew(sample), is(true));
}
@Test
public void VERSION_ISNEW_테스트() throws Exception {
EntityInformation<SampleWithVersion, Long> entityInformation =
new JpaMetamodelEntityInformation<>(SampleWithVersion.class, entityManager.getMetamodel());
SampleWithVersion sampleWithVersion = new SampleWithVersion();
Assert.assertThat(entityInformation.isNew(sampleWithVersion), is(true));
// version 에 값이 들어가는 순간 NewState 가 아님.
sampleWithVersion.setVersion(1L);
Assert.assertThat(entityInformation.isNew(sampleWithVersion), is(false));
// version 에 null 들어가는 순간 newState
sampleWithVersion.setVersion(null);
Assert.assertThat(entityInformation.isNew(sampleWithVersion), is(true));
// Entity 에 @Version 이 들어가는 순간 식별자에 값이 들어가도 newState 상태를 판별하지 못함.
sampleWithVersion.setId(1L);
Assert.assertThat(entityInformation.isNew(sampleWithVersion), is(false));
}
update test
set version + 1
where version = #{version}
@Entity
public class Test implements Persistable<Long> {
@Override
public Long getId() {
return null;
}
@Override
public boolean isNew() {
return false;
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static <T> JpaEntityInformation<T, ?> getEntityInformation(Class<T> domainClass, EntityManager em) {
Assert.notNull(domainClass, "Domain class must not be null!");
Assert.notNull(em, "EntityManager must not be null!");
Metamodel metamodel = em.getMetamodel();
if (Persistable.class.isAssignableFrom(domainClass)) {
return new JpaPersistableEntityInformation(domainClass, metamodel);
} else {
return new JpaMetamodelEntityInformation(domainClass, metamodel);
}
}
public SimpleJpaRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
Assert.notNull(entityInformation, "JpaEntityInformation must not be null!");
Assert.notNull(entityManager, "EntityManager must not be null!");
this.entityInformation = entityInformation;
this.em = entityManager;
this.provider = PersistenceProvider.fromEntityManager(entityManager);
}
// MemberApiController
@PostMapping("/api/training3/members")
public MemberResponse saveMember(@RequestBody @Valid MemberRequest request) {
Member member = Member.create(request);
Long memberId = memberService.saveMember(member);
return new MemberResponse(memberId);
}
// Member.java
public static Member create(MemberRequest request) {
Member member = Member.builder()
.name(request.getName())
.telNo(request.getTelNo())
.age(request.getAge())
.build();
return member;
}
// MemberService.java
public Long saveMember(Member member) {
Member result = memberRepository.save(member);
return result.getId();
}
// MemberApiController
@PostMapping("/api/training3/members")
public MemberResponse saveMember(@RequestBody @Valid MemberRequest request) {
Member member = Member.createContainsId(request);
Long memberId = memberService.saveMember(member);
return new MemberResponse(memberId);
}
// Member.java
public static Member createContainsId(MemberRequest request) {
Member member = Member.builder()
.id(7L)
.name(request.getName())
.telNo(request.getTelNo())
.age(request.getAge())
.build();
return member;
}
// MemberService.java
public Long saveMember(Member member) {
Member result = memberRepository.save(member);
return result.getId();
}
2021-04-27 21:17:20.986 DEBUG 3932 --- [nio-8080-exec-2] org.hibernate.SQL :
select
member0_.member_id as member_i1_1_0_,
member0_.age as age2_1_0_,
member0_.name as name3_1_0_,
member0_.tel_no as tel_no4_1_0_
from
member member0_
where
member0_.member_id=?
2021-04-27 21:17:20.988 TRACE 3932 --- [nio-8080-exec-2] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [7]
2021-04-27 21:17:20.994 DEBUG 3932 --- [nio-8080-exec-2] org.hibernate.SQL :
call next value for hibernate_sequence
2021-04-27 21:17:20.999 DEBUG 3932 --- [nio-8080-exec-2] org.hibernate.SQL :
insert
into
member
(age, name, tel_no, member_id)
values
(?, ?, ?, ?)