【问题标题】:Why cannot I use the operation 'Update" into Spring Data Mongo DB?为什么我不能在 Spring Data Mongodb 中使用“更新”操作?
【发布时间】:2020-08-18 08:16:39
【问题描述】:

我使用 Spring Data MongoDb 将文档保存在数据库中。

@Repository
public interface UserRepository extends MongoRepository<User, ObjectId> {

    Optional<User> findByUsername(String userName);
    
}
@Document(collection = "users")
public class User  {

    @Id
    private ObjectId id;

    @Indexed(unique = true)
    private String username;

...
@Service
public class UserUpdateServiceImpl implements UserUpdateService {

    private UserRepository repository;

    private UserMapper mapper;

    @Autowired
    public UserUpdateServiceImpl(UserRepository repository, UserMapper mapper) {
        this.repository = repository;
        this.mapper = mapper;
    }

    @Override
    public void updateDocumentInCollection(UserDto userDto) {

        User user = mapper.toEntity(userDto);

        repository.save(user);
    }
}

org.springframework.dao.IncorrectResultSizeDataAccessException: 查询 {“$java”:查询:{“用户名”:“用户”},字段:{},排序:{}} 返回非唯一结果。

Update_2

我使用了insert操作

/**
     * Inserts the given entity. Assumes the instance to be new to be able to apply insertion optimizations. Use the
     * returned instance for further operations as the save operation might have changed the entity instance completely.
     * Prefer using {@link #save(Object)} instead to avoid the usage of store-specific API.
     *
     * @param entity must not be {@literal null}.
     * @return the saved entity
     * @since 1.7
     */
    <S extends T> S insert(S entity);
    public void updateUser(UserDto userDto) {

        User user = mapper.toEntity(userDto);

        userRepository.insert(user);
    }

这又导致了一个错误。

org.springframework.dao.DuplicateKeyException: E11000 重复键 错误集合:mongo-spring.users 索引:id dup key: { _id: ObjectId('5f3b786085c7d32787990955') };嵌套异常是 com.mongodb.MongoWriteException: E11000 重复键错误 集合:mongo-spring.users 索引:id 复制键:{ _id: ObjectId('5f3b786085c7d32787990955') }

Update_3

我运行单元测试。

   @Test
    void updateUser() {

        UserDto user = readService.getDataOfUserByName("user");

        user.setEnabled(true);
        user.setAccountNonLocked(true);

        List<Role> authorities = user.getAuthorities();
        authorities.add(Role.ADMIN);
        user.setAuthorities(authorities);


        if(user.getUsername() != null)
            userUpdateService.updateUser(user);

    }

    @Override
    public void updateUser(UserDto userDto) {

        User user = mapper.toEntity(userDto);

        userRepository.save(user);

    }

  • 映射器
public interface CommonMapper<D, E>{

    D toDto(E e);

    E toEntity(D d);

    Iterable<D> toListDto(Iterable<E> entityList);

    Iterable<E> toListEntity(Iterable<D> dtoList);
}
@Mapper(componentModel = "spring")
public interface UserMapper extends CommonMapper<UserDto, User> {
}

现在可以了。

当我尝试更新记录时,出现异常...

【问题讨论】:

  • 尝试使用 insert。
  • M.Ismail 。我试过了,但又是一个错误。

标签: mongodb spring-boot spring-data-jpa


【解决方案1】:

您的代码指定用户名必须是唯一的:

@Indexed(unique = true)
private String username;

但您的数据库中似乎已经有多个条目用于您尝试保存的用户的用户名。

首先,您需要清理现有的重复条目。然后你需要决定在这种情况下你想发生什么:你想更新现有的对象,或者你想返回一个错误,表明用户名已经被占用。

在这两种情况下,您都需要先查找现有用户:

User user = repository.findByUsername(userDto.getUsername());
if(user == null) {
   user = mapper.toEntity(userDto);
}
else {
   mapper.updateUserFromDto(user, userDto);
   //OR: throw an exception
}

repository.save(user);

如果您的用户实体只是 getter/setter,并且您确定 DTO 中的所有字段也都在您的实体中,您也可以重用 mapper.toEntity 进行更新,但我不建议这样做:

User user = repository.findByUsername(userDto.getUsername());
if(user == null) {
   user = mapper.toEntity(userDto);
}
else {
   User updatedUser = mapper.toEntity(userDto);
   updatedUser.setId(user.getId()); // This changes the save from insert to update
   user = updatedUser;
}

repository.save(user);

【讨论】:

  • 没有重复的条目。正是如此。
  • GreyFairer,我想更新现有对象。在我必须获取对象然后更改一些字段之前,我需要更新现有对象。
  • 用户用户 = mapper.toEntity(userDto); - 将 dto 转换为实体的映射器。
  • 将 DTO 转换为实体的映射器是一种反模式。我想如果你覆盖 ID 可能会起作用,但这很难看。
  • 请参阅我的最后一段,了解如何使用现有映射器执行此操作,从实体映射到 DTO 是可以的,这是只读的。另一方面,为了处理创建或更新,从长远来看,使用显式代码比使用映射器更易于维护。它允许进行部分更新或其他用例,使用自动映射器会变得复杂。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-08
  • 1970-01-01
  • 2020-03-22
  • 2021-04-21
  • 2021-05-21
  • 1970-01-01
相关资源
最近更新 更多