The save method using spring-data-jpa in springboot cannot update normally.

  java, question

Make update the simplest way

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

The passed-in method parameter merchant has already set id and some attributes, and other attributes have not been set (i.e null)

The log in the console shows select before update

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

However, the actual update operation did not merge the select result with the parameter merchant passed in the method, promptingADDRESS can not be null

In fact, I have tried to addDynamicUpdateSuch as, but no effect

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

Does it have to be done manually before the update calls savefindOneOnce, do you manually merge the query results and parameters?
Solving. . .

After a long time of investigation, it is true that@ so afraid of troubleThis is what I said.
As for why@DynamicUpdateThe ineffectiveness is still unclear. . .
The solutions that can be found at present are their own.JpaRepository
Here we give our own implementation for reference (Springboot 1.5.6 test passed)

Define one’s ownExtJpaRepositoryInterface

@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);
 bracket

InterfaceExtJpaRepositoryThe implementation of (includinggetNullPropNamesFor custom methods)

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;
 bracket
 
 public SimpleExtJpaRepository(Class<T> domainClass, EntityManager em) {
 super(domainClass, em);
 this.em = em;
 bracket
 
 @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;
 bracket
 return mergedEntity;
 bracket
 
 bracket

Realize one’s ownExtJpaRepositoryFactoryBeanTo replace the originalJpaRepositoryFactoryBean

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);
 bracket
 
 @Override
 protected RepositoryFactorySupport createRepositoryFactory(EntityManager em) {
 return new ExtJpaRepositoryFactory(em);
 bracket
 
 bracket

ExtJpaRepositoryFactoryBeanUsed inExtJpaRepositoryFactory

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);
    }
}

Finally, the entranceApplicationSpecifies to use a custom FactoryBean in

@SpringBootApplication
 @EnableJpaRepositories(repositoryFactoryBeanClass = ExtJpaRepositoryFactoryBean.class)
 public class StartApplication {
 public static void main(String[] args) {
 SpringApplication.run(StartApplication.class, args);
 bracket
 bracket