빡코

[스프링데이터JPA] 새로운 엔티티(Entity)를 구별하는 방법 본문

Java/JPA

[스프링데이터JPA] 새로운 엔티티(Entity)를 구별하는 방법

chris.djang 2023. 5. 12. 13:31

새로운 엔티티를 판단하는 기본전략 
-식별자가 객체일 때 null로 판단 > 새로운 것으로 판단

 
-식별자가 자바 기본타입일 때 0으로 판단

ex) private long id ;  자바의 기본형이기 때문에 객체가 아니고, Null을 넣을 수 없기 때문에 0으로 판다

 

- Persistable인터페이스를 구현해서 판단로직 변경가능(실무에서 사용)

 
id 값이 자동생성이 아닌 특별한 경우에 의하여 직접 채번이 된다고 가정해보자 .
 
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Item {

    @Id
    private String id;

    public Item(String id) {
        this.id = id;
    }
}
@SpringBootTest
class ItemRepositoryTest {


    @Autowired ItemRepository itemRepository;

    @Test
    public void save() {
        Item item = new Item("A");
        itemRepository.save(item);

    }
}

 Persistable인터페이스

Item 엔티티에 Persitable 인터페이스 구현

package study.datajpa.entity;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.hql.spi.id.persistent.PersistentTableBulkIdStrategy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.domain.Persistable;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.time.LocalDateTime;

@Entity
@EntityListeners(AuditingEntityListener.class)
@NoArgsConstructor(access = AccessLevel.PROTECTED)

public class Item implements Persistable<String> {

    @Id
    private String id;

    @CreatedDate //jpa persist가 되기전 호출이 됨
    private LocalDateTime createdDate;

    public Item(String id) {
        this.id = id;
    }

    @Override
    public String getId() {
        return id;
    }

    @Override
    public boolean isNew() {
        //여기서 어떤 조건이면 새것인지 아닌지 로직을 직접 짜야한다.
        return createdDate == null; //-> 새로운 객체로 인정하고 진행
    }
}

> JPA persist가 되기전 createdDate 값체크 

> null 체크로 신규 또는 이미 존재하는 Id인지 확인 
신규인 경우 persist, 기존인 경우 Merge 진행

public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> {

    public <S extends T> S save(S entity) {

       if (entityInformation.isNew(entity)) { // -> 여기에 걸림 
          em.persist(entity);
          return entity;
       } else {
          return em.merge(entity);
       }
    }
}

참고:

JPA 식별자생성전략이@GenerateValue면 save() 호출시점에 식별자가 없으므로 새로운 엔티티로 인식해서 정상동작한다. 그런데 JPA 식별자생성전략이@Id만 사용해서 직접  당이면 이미 식별자값이 있는 상태로 save()를호출한다. 

 

따라서 이 경우 merge()가 호출된다. merge()는 우선 DB를 호출해서 값을 확인하고, DB에 값이 없으면 새로운 엔티티로 인지하므로 매우 비효율적이다. 따라서 Persistable를 사용해서 새로운 엔티티확인여부를 직접 구현하게는 효과적이다.> 참고로 등록시간(@CreatedDate)을조합해서 사용하면이 필드로 새로운 엔티티여부를 편리하게 확인할 수 있다. (@CreatedDate에 값이 없으면 새로운 엔티티로 판단)