Как в spring data jpa бороться с дубликатами? Например мне нужно сохранить профиль с листом тегов и со связью многие ко многим. При сохранении отдельно одинаковых тегов ,которые уже есть или профиля с каскадом - теги дублируются в таблице. Column(unique = true) или NaturalID при дублировании тега по аннотированному полю выкидывает эксепшн о дубликате, но мне нужно игнорить дубликат или перезаписывать. Реализовал следующий пример через спринговский JpaRepository, но опять же эксепшн при сохранении post2, тогда как с post1 всё отлично. Вроде как тривиальная задача, как решить
Т.к. Тег - сущность независимая (она существует независимо от профилей), то и создается она самостоятельно, независимо от профилей, так ведь? Если так, то перед сохранением профиля, сначала, нужно сохранить список тегов.
Чтобы, при этом, избежать ошибки с дубликатами, список тегов сохраняется не сразу списком (например, repo.save(tagList)
), а в цикле, сохраняя результаты в отдельную коллекцию:
for (Tag tag : tagList) {
try {
resultList.add(repo.save(tag));
} catch (Exception e) {
// обработка ошибки
}
}
Затем возвращаем клиенту коллекцию с результатами (или комбинированный ответ с двумя списками - удачно сохраненными тегами и дубликатами).
Column(unique = true) и try {} catch(){}
Update
try{
//your add to db code
}catch(Exception e) {
//do nothing
}
Update 2 Вот так
public void addTag(Tag tag) {
try{
tags.add(tag);
tag.getPosts().add(this);
} catch(Exception e) {}
}
На сколько мне известно, решить эту проблему на уровне JPA нельзя. Но можно нагородить свой велосипед:
@Service
public class TagService {
private final Map<String, Tag> tags = new ConcurrentHashMap<>();
private Lock lock = new Lock();
@Autowired
private TagRepository tagRepository;
@PostConstruct
private void init() {
tagRepository.findAll()
.forEach(i -> tags.put(i.getName(), i));
}
public Tag newTag(String name) {
return tags.computeIfAbsent(name, name -> new Tag(name));
}
public Tag getTag(String name) {
return tags.computeIfAbsent(name, name -> tagRepository.findByName(name));
}
public boolean save() {
boolean locked = false;
try {
locked = lock.tryLock();
if (locked) {
tagRepository.saveAll(tags.values()
.stream()
.filter(i -> i.getId() == null)
.collect(Collectors.toList()))
.forEach(i -> tags.put(i.getName(), i));
return true;
}
}
finally {
if (locked)
lock.unlock();
}
return false;
}
}
Остаётся только получать экземпляры Tag
из сервиса и вызывать tagService.save()
до сохранения сущностей типа Post
.
P.S. Буду очень рад, если кто-нибудь сможет подсказать более изящное решение, но не дёргающее БД чаще.
Виртуальный выделенный сервер (VDS) становится отличным выбором
Как преобразовать xml конфигурацию в webxml в java class?
В проекте есть макеры и кластерыНужно чтобы работало нажатие у обоих