简体   繁体   中英

store spring JPA repository find data to variable before save?

i wanna store spring JPA repository object before it should be saved.

in function update, i wanna store old record data to dbDomain but suddenly after repository.save(updated) the dbDomain changed to new updated data.

any one know how to solve this? thanks

package com.test.admintool.userauth.services;

import java.text.SimpleDateFormat;
import java.util.*;

import com.test.admintool.engine.common.AdminToolFunction;
import com.test.admintool.engine.common.AuditTrailMessage;
import com.test.admintool.engine.common.CopyUtil;
import com.test.admintool.engine.service.AdminService;
import com.test.admintool.engine.service.AuditTrailEventService;
import com.test.admintool.engine.utils.SecurityUtil;
import com.test.admintool.userauth.entity.User;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.GenericTypeResolver;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.transaction.annotation.Transactional;

import com.test.admintool.engine.AdminEntity;
import com.test.admintool.engine.exception.EntityNotFoundException;
import com.test.admintool.engine.repository.AdminRepository;
import com.querydsl.core.types.Predicate;

import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.Table;

@Slf4j
public abstract class AdminServiceImpl<T extends AdminEntity<T>> implements AdminService<T> {

    private static final String AUDIT_ACTION_CREATE = "CREATE";
    private static final String AUDIT_ACTION_UPDATE = "UPDATE";
    private static final String AUDIT_ACTION_DELETE = "DELETE";
    private final AdminRepository<T> repository;

    private final AuditTrailEventService auditTrailEventService;

    protected AdminServiceImpl(AdminRepository<T> repository, AuditTrailEventService auditTrailEventService) {
        this.repository = repository;
        this.auditTrailEventService = auditTrailEventService;
    }

    public T get(Long id) throws EntityNotFoundException {
        return repository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException(String.format("Product %s not found", id)));
    }

    @Transactional
    public T update(T updated) throws EntityNotFoundException {
        T dbDomain = get(updated.getId());
        T updatedData = repository.save(updated);
        produceAuditMessageUpdate(dbDomain, updatedData, AUDIT_ACTION_UPDATE);
        return updatedData;
    }
}

I assume that you are passing a detached entity instance to the update method, and a new transaction is started when entering the method (by the spring transactional aop proxy).
(Otherwise, the dbDomain entry would be resolved from the hibernate 1st level cache to the passed entity instance updated , so that there would not be any property differences.)

When passing the detached instance updated to the save method, the entity manager will merge it into the persistence context. Thereby, it will also check for another already attached instance of the same entity (same ID), and keep the other instance of the entity in sync by copying all values from the newly passed instance to the other attached instance:
https://github.com/hibernate/hibernate-orm/blob/734b80c531bdb2a9bb33971cd57f51fce662e758/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java#L346
(Which makes sense, since you would otherwise end up with different values on the attached entities, and you could not decide which would be persisted to the DB at the end of the transaction.)

To prevent your dbDomain instance being updated, you could manually detach it from the persistence context before calling save(updated) :

T dbDomain = get(updated.getId());
entityManager.detach(dbDomain); // <--
T updatedData = repository.save(updated);    

Alternatively, you may also deep-copy the relevant dbDomain property values.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM