springboot中使用spring-data-jpa的save方法无法正常update

发布于 2022-09-05 10:24:28 字数 834 浏览 15 评论 0

使用最简单的方法进行update操作

public Merchant modifyOne(Merchant merchant) {
    return dao.save(merchant);
}

传递进来的方法参数merchant,已经设置了id和一部分属性,其他属性没有做设置(即null)

控制台中的日志中显示的是先select,再update

Hibernate: select merchant0_.ID as ID1_2_0_, ......
Hibernate: update MERCHANT set ADDRESS=?, ......

但实际update操作时,并没有把select出来的结果和方法中传递进来的参数merchant进行合并, 提示 ADDRESS can not be null

实体上也试过加上DynamicUpdate之类,但没有作用

@Entity
@DynamicInsert
@DynamicUpdate
public class Merchant implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Column(nullable = false, length = 200)
    private String address;
    ......
}

难道一定要在更新调用save之前,手工findOne一次,将查询结果和参数手工合并么?
求解。。。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

狂之美人 2022-09-12 10:24:29

查了好久,确实如 @好怕麻烦 所说,是这个样子。
至于为啥@DynamicUpdate无效还不大清楚。。。
目前能够找到的解决方案是实现自己的JpaRepository
这里给出自己的实现以作参考(springboot 1.5.6测试通过

定义自己的ExtJpaRepository接口

@NoRepositoryBean
public interface ExtJpaRepository<T, ID extends Serializable> extends JpaRepository<T,ID> {
    /**
     * insert or dynamic update entity (will findOne first)
     * @param id entity id
     * @param entity entity
     * @return entity
     */
    T dynamicSave(ID id, T entity);
}

接口ExtJpaRepository的实现(其中getNullPropNames为自定义方法)

public class SimpleExtJpaRepository<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements ExtJpaRepository<T, ID> {
    private final EntityManager em;

    public SimpleExtJpaRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager em) {
        super(entityInformation, em);
        this.em = em;
    }

    public SimpleExtJpaRepository(Class<T> domainClass, EntityManager em) {
        super(domainClass, em);
        this.em = em;
    }

    @Override
    @Transactional
    public T dynamicSave(ID id, T entity) {
        T managedEntity = this.findOne(id);
        T mergedEntity;
        if (managedEntity == null) {
            em.persist(entity);
            mergedEntity = entity;
        } else {
            BeanUtils.copyProperties(entity, managedEntity, BeanUtil.getNullPropNames(entity));
            em.merge(managedEntity);
            mergedEntity = managedEntity;
        }
        return mergedEntity;
    }

}

实现自己的ExtJpaRepositoryFactoryBean以替代原有的JpaRepositoryFactoryBean

public class ExtJpaRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable> extends JpaRepositoryFactoryBean<R, T, I> {
    public ExtJpaRepositoryFactoryBean(Class<? extends R> repositoryInterface) {
        super(repositoryInterface);
    }

    @Override
    protected RepositoryFactorySupport createRepositoryFactory(EntityManager em) {
        return new ExtJpaRepositoryFactory(em);
    }

}

ExtJpaRepositoryFactoryBean中所用到的ExtJpaRepositoryFactory

public class ExtJpaRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory {
    private final EntityManager em;

    public ExtJpaRepositoryFactory(EntityManager em) {
        super(em);
        this.em = em;
    }

    @Override
    protected <T, ID extends Serializable> SimpleExtJpaRepository<?, ?> getTargetRepository(RepositoryInformation information, EntityManager entityManager) {
        JpaEntityInformation<?, Serializable> entityInformation = getEntityInformation(information.getDomainType());
        return getTargetRepositoryViaReflection(information, entityInformation, entityManager);
    }

    @Override
    protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
        if (isQueryDslExecutor(metadata.getRepositoryInterface())) {
            return QueryDslJpaRepository.class;
        } else {
            return SimpleExtJpaRepository.class;
        }
    }

    private boolean isQueryDslExecutor(Class<?> repositoryInterface) {
        return QUERY_DSL_PRESENT && QueryDslPredicateExecutor.class.isAssignableFrom(repositoryInterface);
    }
}

最后,入口Application中指定使用自定义的FactoryBean

@SpringBootApplication
@EnableJpaRepositories(repositoryFactoryBeanClass = ExtJpaRepositoryFactoryBean.class)
public class StartApplication {
    public static void main(String[] args) {
        SpringApplication.run(StartApplication.class, args);
    }
}
美胚控场 2022-09-12 10:24:29

先 findOne 再 save,不然需求需要将属性设置为 null 那咋整

温柔女人霸气范 2022-09-12 10:24:29

BeanUtil.getNullPropNames(entity)这个方法是你自己写的?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文