【问题标题】:cascade save in spring data and mongodb级联保存在spring数据和mongodb中
【发布时间】:2019-09-08 10:30:04
【问题描述】:

我正在实现一个基于spring数据和mongodb的应用程序。

@Document
public class User {

    @Id
    private ObjectId id;

    private String name;

    private Integer age;

    @DBRef
    private Address address;

    @DBRef
    @CascadeSave
    private Set<Action> actions = new HashSet<Action>();

我需要将动作列表作为嵌入文档保存到用户中,为此我实现了自定义级联保存

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CascadeSave {
}

CascadingMongoEventListener.java

public class CascadingMongoEventListener extends AbstractMongoEventListener<Object> {

    @Autowired
    private MongoOperations mongoOperations;

    @Override
    public void onBeforeConvert(final BeforeConvertEvent<Object> event) {
        final 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) {
                            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);
    }

    private static class DbRefFieldCallback implements ReflectionUtils.FieldCallback {
        private boolean idFound;

        @Override
        public void doWith(final Field field) throws IllegalArgumentException, IllegalAccessException {
            ReflectionUtils.makeAccessible(field);
            if (field.isAnnotationPresent(Id.class)) {
                idFound = true;
            }
        }
        public boolean isIdFound() {
            return idFound;
        }
    }
}

我尝试使用操作列表保存用户

Action action = new Action();
action.setDescription("des");
action.setTime(ZonedDateTime.now());
User personHektor = new User();
personHektor.setName("Hektor");
personHektor.setActions(Stream.of(action).collect(Collectors.toSet()));
personRepo.save(personHektor);

但我有这个错误

org.springframework.data.mapping.MappingException: 哎呀,有些东西 出错。孩子没有@Id?

我将项目推送到github 以获得更多可见性

【问题讨论】:

  • 该错误似乎是由于您的CascadingMongoEventListenercheckNSave 方法中抛出MappingException 造成的。您能否详细说明这与 Spring Data MongoDB 的相关程度,并可能添加 AddressAction 类的样子。

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


【解决方案1】:

CascadingMongoEventListener 对照 List 检查 fieldValue,尽管它实际上是 Set
改变它(可能是Collection),MappingException 就会消失。
要另外解决ZonedDateTime 的问题,请注册Converter 以进行转换。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多