spring data mongodb无法在没有id设置的情况下对子对象执行级联保存

问题描述 投票:2回答:3

我正在使用@CascadeSave将子对象保存在单独的集合中。我的文档课程是:

public class FbUserProfile{

    @Id
    private long id;

    @DBRef(lazy=true)
    @CascadeSave()
    private Set<FacebookFriend> friends;

    @DBRef(lazy=true)
    @CascadeSave()
    private Set<FacebookFriendList> customFriendList;
}

public class FacebookFriend{
    @Id
    private long id;
    private String name;
}

public class FacebookFriendList{

    @Id
    private long id;
    private String name;
    private String list_type;
}

我在两个朋友customFriendList中添加了一些对象。并尝试使用以下命令更新fbUserProfile对象:

mongoTemplate.save(fbUserProfile);

注意:db中已存在fbUserProfile。现在我正在更新这个

错误消息:无法在没有设置id的情况下对子对象执行级联保存

如果我删除@CascadeSave。这对我来说可以。我怎么能级联设置对象。我也在使用@CascadeSave和其他对象。它的工作正常,但它们不是设置对象。

java mongodb spring-data-mongodb
3个回答
1
投票

在依赖子对象上设置ID的最佳方法是通过扩展AbstractMongoEventListener类并覆盖onConvert()方法来编写侦听器类。

public class CustomMongoEventListener extends
        AbstractMongoEventListener<Object> {

    @Autowired
    private MongoOperations mongoOperations;

    @Override
    public void onBeforeConvert(final Object entity) {

    if (entity.id == null || entity.id.isEmpty()) {
      entity.id =   generateGuid();   //generate random sequence ID
    }

public static String generateGuid() {
        SecureRandom randomGen = new SecureRandom();
        byte[] byteArray = new byte[16];
        randomGen.nextBytes(byteArray);
        return new Base32().encodeToString(byteArray).substring(0,26);
    }

}

Finally register your custom listener in `your configuration file. For annotation approach use the following code to register :
@Bean
    public CustomMongoEventListener cascadingMongoEventListener() {
        return new CustomMongoEventListener();
    }

0
投票

我在其他地方找到了相同的教程:BaeldungJavaCodeGeeks(这是我所遵循的那个)

我遇到了同样的问题,我可以解决它。可以

当您尝试保留集合时会发生这种情况。集合的项目具有@Id并不重要,因为集合本身不会拥有它。我在EventListener的onBeforeConvert中编辑了代码,以检查您尝试CascadeSave的字段是否是一个集合(在我的例子中是一个List)。如果它是一个列表,你只需循环检查@Id的每个项目并保存它们。

如果它不是一个集合,你仍然必须像以前一样坚持它们

@Override
public void onBeforeConvert(Object source) {
    ReflectionUtils.doWithFields(source.getClass(), new ReflectionUtils.FieldCallback() {

        @Override
        public void doWith(Field field)
                throws IllegalArgumentException, IllegalAccessException {
            ReflectionUtils.makeAccessible(field);

            if (field.isAnnotationPresent(DBRef.class) && field.isAnnotationPresent(CascadeSave.class)){
                final Object fieldValue = field.get(source);

                if(fieldValue instanceof List<?>){
                    for (Object item : (List<?>)fieldValue){
                        checkNSave(item);
                    }
                }else{
                    checkNSave(fieldValue);
                }
            }
        }
    });
}

private void checkNSave(Object fieldValue){
    DbRefFieldCallback callback = new DbRefFieldCallback();
    ReflectionUtils.doWithFields(fieldValue.getClass(), callback);

    if (!callback.isIdFound()){
        throw new MappingException("Oops, something went wrong. Child doesn't have @Id?");
    }

    mongoOperations.save(fieldValue);
}

0
投票

如果您有一个列表,上述解决方案可以正常工作。但是我们可以避免为列表中的每个元素触发保存查询,因为它会降低性能。这是我从上面的代码中找到的解决方案。

 @Override
  public void onBeforeConvert(BeforeConvertEvent<Object> event) {
      Object source = event.getSource(); 
      ReflectionUtils.doWithFields(source.getClass(), new ReflectionUtils.FieldCallback() {

          @Override
          public void doWith(Field field)
                  throws IllegalArgumentException, IllegalAccessException {
              ReflectionUtils.makeAccessible(field);

              if (field.isAnnotationPresent(DBRef.class) && field.isAnnotationPresent(CascadeSave.class)){
                  final Object fieldValue = field.get(source);

                  if(fieldValue instanceof List<?>){
                      for (Object item : (List<?>)fieldValue){
                          checkNAdd(item);
                      }
                  }else{
                      checkNAdd(fieldValue);
                  }
                  mongoOperations.insertAll(documents);
              }
          }
      });
  }

  private void checkNAdd(Object fieldValue){
      DbRefFieldCallback callback = new DbRefFieldCallback();
      ReflectionUtils.doWithFields(fieldValue.getClass(), callback);

      if (!callback.isIdFound()){
          throw new MappingException("Oops, something went wrong. Child doesn't have @Id?");
      }

      documents.add(fieldValue);
  }
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.