HashSet в @Document, где сущность использует уникальный идентификатор, DuplicatekeyException - PullRequest
0 голосов
/ 17 марта 2020

Я использую Spring Boot и данные Spring MongoDB (+ mongodb-реагирующий, но я думаю, что это не важно для этой проблемы). Для некоторой автогенерации я использую Lombok.

У меня есть User сущность:

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
...

@Document
@Getter
@Setter
@NoArgsConstructor
@EqualsAndHashCode(exclude = {"friends"})
public class User {
  @Id
  String id;

  @Indexed(unique=true)
  String someOtherIdentifier;

  Set<User> friends;

  ....

  public User(String someOtherIdentifier) {
    this.someOtherIdentifier = someOtherIdentifier;
    this.friends = new HashSet<>();
  }

}

Когда я теперь запускаю тесты, где я создаю две User сущности друг за другом, выдается следующее исключение:

 E11000 duplicate key error collection: managingService.user index: friends.hashedIdentifier dup key: { : null }; nested exception is com.mongodb.MongoWriteException: E11000 duplicate key error collection: managingService.user index: friends.hashedIdentifier dup key: { : null }))

Тест выглядит примерно так (я также получаю исключение при тестировании вручную):

    @Test
    void create() {
        User entity = new User("1");
        User newEntity = new User("2");

        StepVerifier.create(repository.save(entity))
                .expectNextMatches(entity::equals)
                .verifyComplete();

        StepVerifier.create(repository.save(newEntity))
                .expectNextMatches(newEntity::equals)
                .verifyComplete();

        StepVerifier.create(repository.count()).expectNext(2L).verifyComplete();
    }

Я вижу, что проблема вызвана набором friends, где вторая сущность имеет тот же User в наборе. Конечно, у разных пользователей может быть один и тот же друг, поэтому в этом наборе он не должен проверять уникальные идентификаторы. Любая помощь о том, как решить эту проблему, очень ценится!

1 Ответ

0 голосов
/ 23 марта 2020

Аннотация @Indexed также сравнивается с Set<User>, что приводит к двум уникальным индексам.

"someOtherIdentifier" : 1
"friends.someOtherIdentifier" : 1

Обратите внимание на отключение автоматических индексов и вместо этого используйте ручные индексы через IndexOperations.

Index index = new Index("someOtherIdentifier", Direction.ASC).unique();
template.indexOps(User.class).ensureIndex(index);
...