spring-projects / spring-data-jpa

Simplifies the development of creating a JPA-based data access layer.
https://spring.io/projects/spring-data-jpa/
Apache License 2.0
2.98k stars 1.41k forks source link

The getId method was not called #3470

Closed lyworry closed 4 months ago

lyworry commented 4 months ago

The Class Document extends BaseEntity implements Persistable<Long> and new HashMap<Long,Document> to storage the document that have been stored to the mysql (The key is document.md5 and the value is document). I create two repositories public interface JpaDocumentRepository extends CrudRepository<Document,Long> and public interface ElasticSearchDocumentRepository extends CrudRepository<Document,Long>.i find JpaDocumentRepository.save() was not call method 'getId()' that implement,but ElasticSearchDocumentRepository.save() will call the method getId(). If I were to call JpaDocumentRepository. save to save the two document has the same md5, will produce two records, because there is no call getId() and ElasticSearchDocumentRepository.save will insert and update, a record only. I think implements Persistable is want to judge the object isNew,and execut update or insert.In fact,isNew only is only used to determine execut entityManager.persist(entity) or entityManager.merge(entity).entityManager.merge(entity) performs an insert or update operation depending on whether theid is empty.This does not lose the meaning of such a design?

@Setter
//@Getter
@MappedSuperclass
public class BaseEntity {

    @Id
    @GenericGenerator(name = "snowFlakeIdGenerator", type = SnowFlakeIdGenerator.class)
    @GeneratedValue(generator = "snowFlakeIdGenerator")
    public Long id;

    @CreatedDate
    private Date createdDate;

    @LastModifiedDate
    private Date lastModifiedDate;

    @CreatedBy
    private String createdBy;

    @LastModifiedBy
    private String lastModifiedBy;
}
@Setter
@Getter
@Entity
@org.springframework.data.elasticsearch.annotations.Document(indexName = "document")
public class Document extends BaseEntity implements Persistable<Long> {

    /**
     * 标题
     */
    private String title;

    @Lob
    @Column(columnDefinition = "longtext")
    @Field(type = FieldType.Text, analyzer = "ik_max_word", store = false)
    private String content;

    /**
     * 角色code列表
     */
    @Convert(converter = JpaConverterList.class)
    private List<String> roleCodeList;

    /**
     * 标签code列表
     */
    @Convert(converter = JpaConverterList.class)
    private List<String> tagCodeList;

    /**
     * 文本摘要
     */
    private String md5;

    @Nullable
    @Override
    public Long getId() {
        Document document = Cache.cacheMap.get(md5);
        if (document != null) {
            return document.id;
        }
        return this.id;
    }

    @Override
    public boolean isNew() {
        return Cache.cacheMap.get(md5) == null;
    }

}
mp911de commented 4 months ago

Persistable is a Spring Data API to determine the identifier and whether an object is new or not. Persistable is only used by Spring Data modules in which we fully control the object lifecycle such as Elasticsearch.

JPA handles object lifecycles on its own with the concept of attached entities hence Spring Data JPA doesn't make use of Persistable for inserts vs. updates, instead, what you already found, whether to call EntityManager.merge(…) vs. EntityManager.persist(…).

Generally speaking, if you use a single cache (Cache.cacheMap.get(md5)) for two persistence technologies, after associating the object with your cache, all related store modules will use the same outcome for isNew.

Ideally, you use the md5 value as primary key if that is what you're looking for.

lyworry commented 4 months ago

Persistable seem to be unuseful in spring data jpa.All operations depend on whether id has value.I can't imagine what can i do with Persistable.I think spring data jpa and spring data elasticsearch,they all belong to spring data, they implements Persistable,They should have the same behavior

  1. if document ’s id has value and isNew=true will throw exception, isNew=false will select by id and update;
  2. if document ’s id is null and isNew=true will insert,isNew=false wll also insert;