Обновление аудита и версионного объекта с использованием JpaRepository - PullRequest
0 голосов
/ 19 сентября 2018

У меня есть приложение Spring Boot, которое имеет простое Entity, JpaRepository и Service.

Entity :

@Getter
@Setter
@EntityListeners(AuditingEntityListener.class)
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Long id;

    @Version
    private Long version;

    @CreatedDate
    private LocalDateTime created;

    @LastModifiedDate
    private LocalDateTime lastModified;

    @CreatedBy
    private String createdBy;

    @LastModifiedBy
    private String lastModifiedBy;

    private String name;

    private String email;

}

JpaRepository :

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

Сервис :

@Service
class UserService {

    @Autowired
    private UserRepository userRepository;

    @Transactional
    public User create(User user) {
        Assert.isNull(user.getId(), "Can't create an existing user!");
        return userRepository.saveAndFlush(user);
    }

    @Transactional
    public User update(User user) {
        Assert.notNull(user.getId(), "Can't update a new user!");
        return userRepository.saveAndFlush(user);
    }

}

В моем реальном приложении аннотация @Transactional установлена ​​в RestController, но create() иupdate() никогда не выполняются в одной и той же транзакции

Когда я создаю нового пользователя следующим образом:

User user = new User();
user.setName("user");
user.setEmail("user@email");
userService.create(user);

Spring автоматически устанавливает все свойства аудита (созданные, lastModified, ...) и версия до 0.

Но когда я обновляю существующего пользователя следующим образом:

User user = new User();
user.setId(1L);             // Id of the User I want to update
user.setVersion(5L)         // Current version is 5L
user.setName("user");  
user.setEmail("new@email"); // I want to update only the email
userService.update(user);

я получаю эту ошибку:

org.postgresql.util.PSQLException: ERROR: null value in column "created" violates not-null constraint

, что означает, чтоSpring Auditing не обрабатывает свойство created.

Чтобы исправить это, я изменил свой метод update в UserService следующим образом:

@Transactional
public User update(User user) {
    Assert.notNull(user.getId(), "Can't update a new user!");
    User original = userRepository.getOne(user.getId())
    original.setVersion(user.getVersion());
    original.setName(user.getName());
    original.setEmail(user.getEmail());
    return userRepository.saveAndFlush(original);
}

это исправило PSQLException но тогда версия больше не проверяется.Это означает, что если я установлю версию, отличную от текущей версии в базе данных, я не получу ошибку ObjectOptimisticLockingFailureException, и обновленный пользователь будет сохранен в базе данных без ошибок.

IЯ могу заменить .getOne() на .findById(), но ничего не изменится

В конце я смог исправить обе мои проблемы следующим образом:

@Transactional
public User update(User user) {
    Assert.notNull(user.getId(), "Can't update a new user!");
    Assert.notNull(user.getVersion(), "Version must be defined!");
    User original = userRepository.getOne(user.getId())
    User update = new User();
    update.setId(original.getId());
    update.setCreated(original.getCreated());
    update.setCreatedBy(original.getCreatedBy());
    update.setVersion(user.getVersion());
    update.setName(user.getName());
    update.setEmail(user.getEmail());
    return userRepository.saveAndFlush(update);
}

Мне все еще нужно проверить, что версия не равна нулю, иначе пользователь будет сохранен без проверки версии

, теперь поля аудита не выдают PSQLException, а версия проверяется перед обновлением и ObjectOptimisticLockingFailureException это бросить, когда это неправильно.

Но это решение ужасно , потому что мне нужно копировать свойства влево и вправо, а в больших объектах будет легко что-то забыть.

Знаете ли вы лучшее решение этой проблемы?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...