使用jpa之动态插入与修改(重写save)

网友投稿 288 2022-09-13


使用jpa之动态插入与修改(重写save)

目录jpa之动态插入与修改(重写save)1.动态插入2.重写save(修改)3.启动类扩展JPA方法,重写save方法为什么要重构save?一、重写save二、扩张jpa方法

jpa之动态插入与修改(重写save)

1.动态插入

@Data

@Entity

@DynamicInsert

@Table(name = "cpu_dynamics_information")

@EntityListeners(AuditingEntityListener.class)

public class CpuDynamicsInformation extends CommonEntity implements Serializable {

private static final long serialVersionUID = -662804563658253624L;

// cpu动态属性

private Integer cpuCore;

// cpu用户使用率

private Double cpuUseRate;

// cpu系统使用率

private Double cpuSysRate;

// cpu等待率

private Double cpuWaitRate;

// cpu空闲率

private Double cpuIdleRate;

// cpu总的使用率

private Double cpuCombineRate;

private Long serverId;

}

关键注解:

@DynamicInsert

@EntityListeners(AuditingEntityListener.class)

2.重写save(修改)

@SuppressWarnings(value = "all")

public class JpaRepositoryReBuild extends SimpleJpaRepository {

private final JpaEntityInformation entityInformation;

private final EntityManager em;

@Autowired

public JpaRepositoryReBuild(

JpaEntityInformation entityInformation, EntityManager entityManager) {

super(entityInformation, entityManager);

this.entityInformation = entityInformation;

this.em = entityManager;

}

/** 通用save方法 :新增/选择性更新 */

@Override

@Transactional

public S save(S entity) {

// 获取ID

ID entityId = (ID) this.entityInformation.getId(entity);

T managedEntity;

T mergedEntity;

if (entityId == null) {

em.persist(entity);

mergedEntity = entity;

} else {

managedEntity = this.findById(entityId).get();

if (managedEntity == null) {

em.persist(entity);

mergedEntity = entity;

} else {

BeanUtils.copyProperties(entity, managedEntity, getNullProperties(entity));

em.merge(managedEntity);

mergedEntity = managedEntity;

}

}

return entity;

}

/** 获取对象的空属性 */

private static String[] getNullProperties(Object src) {

// 1.获取Bean

BeanWrapper srcBean = new BeanWrapperImpl(src);

// 2.获取Bean的属性描述

PropertyDescriptor[] pds = srcBean.getPropertyDescriptors();

// 3.获取Bean的空属性

Set properties = new HashSet<>();

for (PropertyDescriptor propertyDescriptor : pds) {

String propertyName = propertyDescriptor.getName();

Object propertyValue = srcBean.getPropertyValue(propertyName);

if (StringUtils.isEmpty(propertyValue)) {

srcBean.setPropertyValue(propertyName, null);

http:// properties.add(propertyName);

}

}

return properties.toArray(new String[0]);

}

}

3.启动类

@EnableJpaAuditing

@SpringBootApplication(exclude = MongoAutoConfiguration.class)

@EnableJpaRepositories(

value = {"com.fooww.research.repository", "com.fooww.research.shiro.repository"},

repositoryBaseClass = JpaRepositoryReBuild.class)

public class MonitorServerApplication {

public static void main(String[] args) {

SpringApplication.run(MonitorServerApplication.class, args);

}

}

关键注释:

EnableJpaRepositories 扫描的repository包

repositoryBaseClass 重写的save类

EnableJpaAuditing 使@EntityListeners(AuditingEntityListener.class) 生效

扩展JPA方法,重写save方法

为什么要重构save?

jpa提供的save方法会将原有数据置为null,而大多数情况下我们只希望跟新自己传入的参数,所以便有了重写或者新增一个save方法。

本着解决这个问题,网上搜了很多解决方案,但是没有找到合适的,于是自己研究源码,先展示几个重要源码

1、SimpleJpaRepository方法实现类,由于代码过多只展示部分源码

public class SimpleJpaRepository implements JpaRepository, JpaSpecificationExecutor {

private static final String ID_MUST_NOT_BE_NULL = "The given id must not be null!";

private final JpaEntityInformation entityInformation;

http:// private final EntityManager em;

private final PersistenceProvider provider;

@Nullable

private CrudMethodMetadata metadata;

public SimpleJpaRepository(JpaEntityInformation entityInformation, EntityManager entityManager) {

Assert.notNull(entityInformation, "JpaEntityInformation must not be null!");

Assert.notNull(entityManager, "EntityManager must not be null!");

this.entityInformation = entityInformation;

this.em = entityManager;

this.provider = PersistenceProvider.fromEntityManager(entityManager);

}

public SimpleJpaRepository(Class domainClass, EntityManager em) {

this(JpaEntityInformationSupport.getEntityInformation(domainClass, em), em);

}

public void setRepositoryMethodMetadata(CrudMethodMetadata crudMethodMetadata) {

this.metadata = crudMethodMetadata;

}

@Nullable

protected CrudMethodMetadata getRepositoryMethodMetadata() {

return this.metadata;

}

protected Class getDomainClass() {

return this.entityInformation.getjavaType();

}

private String getDeleteAllQueryString() {

return QueryUtils.getQueryString("delete from %s x", this.entityInformation.getEntityName());

}

@Transactional

public S save(S entity) {

if (this.entityInformation.isNew(entity)) {

this.em.persist(entity);

return entity;

} else {

return this.em.merge(entity);

}

}

}

2、JpaRepositoryFactoryBean

public class JpaRepositoryFactoryBean, S, ID> extends TransactionalRepositoryFactoryBeanSupport {

@Nullable

private EntityManager entityManager;

public JpaRepositoryFactoryBean(Class extends T> repositoryInterface) {

super(repositoryInterface);

}

@PersistenceContext

public void setEntityManager(EntityManager entityManager) {

this.entityManager = entityManager;

}

public void setMappingContext(MappingContext, ?> mappingContext) {

super.setMappingContext(mappingContext);

}

protected RepositoryFactorySupport doCreateRepositoryFactory() {

Assert.state(this.entityManager != null, "EntityManager must not be null!");

return this.createRepositoryFactory(this.entityManager);

}

protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {

return new JpaRepositoryFactory(entityManager);

}

public void afterPropertiesSet() {

Assert.state(this.entityManager != null, "EntityManager must not be null!");

super.afterPropertiesSet();

}

}

根据源码及网上资料总结如下方案

一、重写save

优势:侵入性小,缺点将原方法覆盖。

创建JpaRepositoryReBuild方法继承SimpleJpaRepository。

直接上代码

public class JpaRepositoryReBuild extends SimpleJpaRepository {

private final JpaEntityInformation entityInformation;

private final EntityManager em;

@Autowired

public JpaRepositoryReBuild(JpaEntityInformation entityInformation, EntityManager entityManager) {

super(entityInformation, entityManager);

this.entityInformation = entityInformation;

this.em = entityManager;

}

/**

* 通用save方法 :新增/选择性更新

*/

@Override

@Transactional

public S save(S entity) {

//获取ID

ID entityId = (ID) this.entityInformation.getId(entity);

T managedEntity;

T mergedEntity;

if(entityId == null){

em.persist(entity);

mergedEntity = entity;

}else{

managedEntity = this.findById(entityId).get();

if (managedEntity == null) {

em.persist(entity);

mergedEntity = entity;

} else {

BeanUtils.copyProperties(entity, managedEntity, getNullProperties(entity));

em.merge(managedEntity);

mergedEntity = managedEntity;

}

}

return entity;

}

/**

* 获取对象的空属性

*/

private static String[] getNullProperties(Object src) {

//1.获取Bean

BeanWrapper srcBean = new BeanWrapperImpl(src);

//2.获取Bean的属性描述

PropertyDescriptor[] pds = srcBean.getPropertyDescriptors();

//3.获取Bean的空属性

Set properties = new HashSet<>();

for (PropertyDescriptor propertyDescriptor : pds) {

String propertyName = propertyDescriptor.getName();

Object propertyValue = srcBean.getPropertyValue(propertyName);

if (StringUtils.isEmpty(propertyValue)) NTvHzn{

srcBean.setPropertyValue(propertyName, null);

properties.add(propertyName);

}

}

return properties.toArray(new String[0]);

}

}

启动类加上JpaRepositoryReBuild 方法

@EnableJpaRepositories(value = "com.XXX", repositoryBaseClass = JpaRepositoryReBuild.class)

@SpringBootApplication

@EnableDiscoveryClient // 即消费也注册

public class SystemApplication {

public static void main(String[] args) {

SpringApplication.run(SystemApplication.class, args);

}

}

二、扩张jpa方法

1、新建新增方法接口BaseRepository

@NoRepositoryBean

public interface BaseRepository extends JpaRepository {

/**

* 保存但不覆盖原有数据

* @param entity

* @return

*/

T saveNotNull(T entity);

}

2、创建BaseRepositoryImpl方法

@NoRepositoryBean

public class BaseRepositoryImpl extends SimpleJpaRepository implements BaseRepository {

private final JpaEntityInformation entityInformation;

private final EntityManager em;

public BaseRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) {

super(entityInformation,entityManager);

this.entityInformation = entityInformation;

this.em = entityManager;

}

public BaseRepositoryImpl(Class domainClass, EntityManager em) {

this(JpaEntityInformationSupport.getEntityInformation(domainClass, em), em);

}

@Override

@Transactional

public T saveNotNull(T entity) {

//获取ID

ID entityId = (ID) this.entityInformation.getId(entity);

T managedEntity;

T mergedEntity;

if(entityId == null){

em.persist(entity);

mergedEntity = entity;

}else{

managedEntity = this.findById(entityId).get();

if (managedEntity == null) {

em.persist(entity);

mergedEntity = entity;

} else {

BeanUtils.copyProperties(entity, managedEntity, getNullProperties(entity));

em.merge(managedEntity);

mergedEntity = managedEntity;

}

}

return mergedEntity;

}

private static String[] getNullProperties(Object src) {

//1.获取Bean

BeanWrapper srcBean = new BeanWrapperImpl(src);

//2.获取Bean的属性描述

PropertyDescriptor[] pds = srcBean.getPropertyDescriptors();

//3.获取Bean的空属性

Set properties = new HashSet<>();

for (PropertyDescriptor propertyDescriptor : pds) {

String propertyName = propertyDescriptor.getName();

Object propertyValue = srcBean.getPropertyValue(propertyName);

if (StringUtils.isEmpty(propertyValue)) {

srcBean.setPropertyValue(propertyName, null);

properties.add(propertyName);

}

}

return properties.toArray(new String[0]);

}

}

3、创建工厂BaseRepositoryFactory

public class BaseRepositoryFactory, T, ID extends Serializable> extends JpaRepositoryFactoryBean {

public BaseRepositoryFactory(Class extends R> repositoryInterface) {

super(repositoryInterface);

}

@Override

protected RepositoryFactorySupport createRepositoryFactory(EntityManager em) {

return new MyRepositoryFactory(em);

}

private static class MyRepositoryFactory extends JpaRepositoryFactory {

private final EntityManager em;

public MyRepositoryFactory(EntityManager em) {

super(em);

this.em = em;

}

@Override

protected Object getTargetRepository(RepositoryInformation information) {

return new BaseRepositoryImpl((Class) information.getDomainType(), em);

}

@Override

protected Class getRepositoryBaseClass(RepositoryMetadata metadata) {

return BaseRepositoryImpl.class;

}

}

}

4、启动类引入

@EnableJpaRepositories(repositoryFactoryBeanClass = BaseRepositoryFactory.class, basePackages ="com.XXX")

@SpringBootApplication

@EnableDiscoveryClient // 即消费也注册

public class SystemApplication {

public static void main(String[] args) {

SpringApplication.run(SystemApplication.class, args);

}

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:OpenNMS系统安装(Linux-CentOS7)
下一篇:SDN in Action: Practice NETCONF/RESTCONF and YANG with OpenDaylight and IOS XRv(sdn网络)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~