Spring Data JPA において、 外部制約違反でエンティティをパーシストできない現象について

More than 1 year has passed since last update.


概要

Spring Data JPA において、Cascase.ALL のリレーションがあるエンティティのインサート時に、Many 側からの INSERT が発生したため、外部制約違反が発生してしまう現象が発生しました。

下記の例ですと、order から insert が実行されるので、親である user に insert される order の userNo が存在していません。

そのため、外部キー制約にて例外が発生しました。


User.java

@Entity

@Getter
@NoArgsConstructor
public class User {

@Id
private String userNo;

@OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<Order> orders;
}



Order.java

@Entity

@NoArgsConstructor
public class Order {

@Getter
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;

@Getter
private String userNo;

@ManyToOne
@JoinColumn(name = "user_no", updatable = false, insertable = false)
private User user;
}


例外が発生する SQL

insert into order (id, user_no ...) values (1, '001' ...);


原因

JpaRepository にて該当の User オブジェクトを取得しているため、EntityManager の管理下にあるためでした。

EntityManager#detach を実行することで、user から insert が実行され、正常に order を登録できました。


UserRepository.java

@Repository
public interface UserRepository extends JpaRepository<User, Integer> {

@EntityGraph(value = "user", attributePaths = "orders", type = EntityGraph.EntityGraphType.LOAD)
Optional<User> findOne(String userNo);
}



UserService.java

@Service

@RequiredArgsConstructor
@Slf4j
@Transactional
public class UserServiceImpl implements UserService {

private final UserRepository userRepository;
private final EntityManager em;

@Override
public User getUser(String userNo) {
Optional<User> optional = userRepository.findOne(userNo);
User result = optional.get();
em.detach(result);
return result;
}
}



補足

今回の要件では、登録されている User オブジェクトの洗い替えを実行したいために、登録対象の User オブジェクトを削除するため、

上記のメソッドを実行しています。