技術とか戦略とか

IT技術者が技術や戦略について書くブログです。

JPAでのDelete実装方法三選

Spring Framework + JPAでのDelete実装方法について、調べるのに少し苦労しましたので、実装方法をまとめます。
 
----
 
1.CrudRepositoryインターフェースのメソッドを利用する
全件削除、1つ~複数のエンティティクラスのインスタンスを指定して削除、1つ~複数の主キーの値を指定して削除するだけであれば、CrudRepositoryインターフェースのメソッドを利用することでシンプルな実装で対応できます。
CrudRepositoryインターフェースのメソッドについては、以下の公式ドキュメントで説明されています。
https://spring.pleiades.io/spring-data/commons/docs/current/api/org/springframework/data/repository/CrudRepository.html
 
以下は、全件削除を行うサンプルコードです。
(コードは一部を抜き出したものです)
 
【エンティティクラス】
・Message.java
package com.example.demo.domain.message.model;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;

import lombok.Data;

@Entity
@Table(name="message")
@Data
public class Message {
    
    // ID
    @Id // 主キーに対して付与
    private int id;

    // 投稿内容
    private String text;
    
    // 種別ID
    private String kindId;
}
 
【Daoクラス】
・MessageDao.java
package com.example.demo.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.example.demo.domain.message.model.Message;

public interface MessageDao extends JpaRepository<Message,String> {

}
 
【Serviceクラス】
今回の例では、ServiceクラスにCrudRepositoryインターフェースのメソッドを記述します。

・MessageService.java
package com.example.demo.domain.message.service;

import org.springframework.transaction.annotation.Transactional;

public interface MessageService {

    /** 削除(全件) */
    @Transactional // メソッドを抜ける時にcommit発行
    public void deleteAll();

}
 
・MessageServiceImpl.java
package com.example.demo.domain.message.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.demo.domain.message.service.MessageService;
import com.example.demo.repository.MessageDao;

@Service
public class MessageServiceImpl implements MessageService {

    @Autowired
    private MessageDao dao;
    
    /** 全件削除 */
    @Override
    public void deleteAll() {
        dao.deleteAll();
        return;
    }

}
 
【Controllerクラス】
今回のサンプルでは省略しますが、Serviceクラスのメソッドを呼び出すことで、削除が実行されます。
 
----
 
2.SQL文を直接記述する
極力避けるべきではありますが、要件が複雑な場合はSQL文を直接記述せざるを得なくなる場合があります。
今回の例では、「主キー以外の項目を削除条件に指定する」「削除件数を取得する」という要件を満たすためにSQL文を直接記述します。
 
【エンティティクラス】
先ほどの例と同じです。
 
【Daoクラス】
・MessageDao.java
package com.example.demo.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.example.demo.domain.message.model.Message;

public interface MessageDao extends JpaRepository<Message,String> {

    /* JPQL定数 */
    final String JPQL_DELETE_MESSAGE_BY_KINDID = " DELETE "
                                                + " FROM Message m "
                                                + " WHERE m.kindId = :kindId ";
    
    /** 削除(種別ID指定) */
    @Modifying
    @Query(JPQL_DELETE_MESSAGE_BY_KINDID)
    public long deleteByKindId(String kindId) throws DataAccessException;

}
 
【Serviceクラス】
・MessageService.java
package com.example.demo.domain.message.service;

import org.springframework.transaction.annotation.Transactional;

public interface MessageService {

    /** 削除(全件) */
    @Transactional // メソッドを抜ける時にcommit発行
    public long deleteAll();

}
 
・MessageServiceImpl.java
package com.example.demo.domain.message.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.demo.domain.message.service.MessageService;
import com.example.demo.repository.MessageDao;

@Service
public class MessageServiceImpl implements MessageService {

    @Autowired
    private MessageDao dao;
    
    /** 種別ID="0001"を削除 */
    @Override
    public long deleteAll() {
        return dao.deleteByKindId("0001");
    }

}
 
【Controllerクラス】
Serviceクラスのメソッドを呼び出すことで、削除が実行されます。
 
----
 
3.Derived deleteBy Methodsを使用する
「主キー以外の項目を削除条件に指定する」「削除件数を取得する」という要件であれば、Derived deleteBy Methodsを使用することで、SQL文を直接記述せずとも実現できます。
Derived deleteBy Methodsについては、以下のページで使い方が解説されています。
https://www.baeldung.com/spring-data-jpa-deleteby
 
以下は使用例です。
 
【エンティティクラス】
先ほどの例と同じです。
 
【Daoクラス】
・MessageDao.java
package com.example.demo.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.example.demo.domain.message.model.Message;

public interface MessageDao extends JpaRepository<Message,String> {

    /** 削除(種別ID指定) */
    public Long deleteByKindId(String kindId);

}
 
【Serviceクラス】
【Controllerクラス】
先ほどの例と同じです。