java - Spring BootでJPAを使用して保存するときに、更新されて保存されたエンティティを取得する方法はありますか?

okwaves2024-01-24  4

まず第一に、これがリクエストをキャッシュしているのか、あるいは単にフィールドにデータを入力していないだけなのか、わかりません。

CmsRegions というエンティティがあり、次の内容が含まれています。

public class CmsRegions extends Model implements Serializable {
       
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private Integer id;
    
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 100)
    @Column(name = "name")
    private String name;
    
    @Lob
    @Size(max = 65535)
    @Column(name = "description")
    private String description;
    
    @Size(max = 2)
    @Column(name = "lang")
    private String lang;
    
    @Size(max = 2)
    @Column(name = "locale")
    private String locale;
    
    @Basic(optional = false)
    @NotNull
    @Column(name = "is_active")
    private short isActive;
    
    @Column(name = "parent_id")
    private Integer parentId;
        
    @Basic(optional = false)
    @Column(name = "created", insertable = false, updatable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date created;
    
    @Basic(optional = false)
    @Column(name = "modified", insertable = false, updatable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date modified;


    ...getters and setters etc...
}

次のようにエンティティを取得するための基本的なリポジトリ呼び出しがあります。

@NoRepositoryBean
public interface BaseCmsRepository<T extends Serializable> extends JpaRepository<T, Long> {
    
    @Query("SELECT a FROM #{#entityName} a WHERE a.id = :id")
    List<T> getById(
            @Param("id") Integer id
    );
    

エンティティを保存すると、データベースに次のテーブルに保存されます。

CREATE TABLE `cms_regions` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  `description` text,
  `lang` char(2) DEFAULT NULL,
  `locale` char(2) DEFAULT NULL,
  `is_active` tinyint unsigned NOT NULL DEFAULT '0',
  `parent_id` int unsigned DEFAULT NULL,
  `created` datetime DEFAULT CURRENT_TIMESTAMP,
  `modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8;

作成および変更されたフィールドは期待どおりに適切に設定されますが、保存アクションから取得した結果のエンティティには、作成日および変更日の NULL 値が含まれています。

テストを実行しました。最後の挿入 ID は 31 だったので、次のコードをコントローラーに追加しました。

    cmsService.saveRegion(region); // save entity

    CmsRegions  testreg1 = cmsService.getRegion(1);
    CmsRegions  testreg2 = cmsService.getRegion(region.getId());
    CmsRegions  testreg3 = cmsService.getRegion(30);
    CmsRegions  testreg4 = cmsService.getRegion(32);  // currently saved entity new ID (32)

これを実行すると、testreg1 には、希望どおり、作成日と変更日が Date オブジェクトとして含まれていました。 testreg2 には null 値が含まれていました (region.getId() = 32この点)。 testreg3 には、作成および変更された Date オブジェクトが含まれていました。

最終値 testreg4 も NULL でした。問題は、次回実行したときに、testreg4 に作成および変更された値が含まれていることです。しかし、次の反復、testreg2 の (33) は再び NULL でした。

これがキャッシュの問題なのか、それとも何なのかはわかりません。呼び出しが終了する前にデータベース値を取得しようとすると、データがデータベース内にある(ブレークポイントで確認されている)にもかかわらず、結果のフィールドは常に null になるようです。次回実行すると、値が設定されます。

なぜですか?これらの値を取得するには何をする必要がありますか?

----------------------------------

JpaRepository#save または同様のインターフェイスでこのメソッドを使用して保存すると、データベースからエンティティが返されます。そのまま使えます。最も一般的には、生成された ID を入力するために使用されます。

assertNull(entity.getId());
entity = entityRepository.save(entity);
assertNotNull(entity.getId());

他のプロセスがデータを変更しており、永続化コンテキストが更新されていない場合は、少し複雑になります。その場合、別のクエリが必要になります。これを回避するには、EntityManager#refresh を使用し、「再取得」したいエンティティを渡します。データベースから。現時点では、そのメカニズムが spring-data-jpa に存在するかどうかはわかりません。

3

em.refresh を使用しようとしましたが、このアプローチでもデータベースに対して新しいクエリを完全に実行していました。過去のレコードは機能するのに、現在のレコードは機能しないのはなぜですか?

– バリー・チャップマン

2020 年 9 月 3 日 2:54

@BarryChapman 保存時に返されたエンティティを使用できますが、それが不可能な場合、または他の変更がある場合は、別のクエリが必要です。私の編集をチェックしてください。

– アンドロニカス

2020 年 9 月 3 日 2:59

カスタム リポジトリを追加して拡張し、refresh メソッドを使用します。追加するまでに数分かかります

– バリー・チャップマン

2020 年 9 月 3 日 3:04

総合生活情報サイト - OKWAVES
総合生活情報サイト - OKWAVES
生活総合情報サイトokwaves(オールアバウト)。その道のプロ(専門家)が、日常生活をより豊かに快適にするノウハウから業界の最新動向、読み物コラムまで、多彩なコンテンツを発信。