原因: jpa 没有类似于mybatis的那种 拼接sql的方式 想动态更新 需要使用
CriteriaUpdate的方式 去一直拼接,其实大多数场景只要传入一个非空实体类,去动态拼接sql
1.定义实体类 继承一个统一的类型
@Data @ToString @Entity @Table(name = "sys_user") @DynamicInsert @JsonIgnoreProperties(ignoreUnknown = true) @EntityListeners(SysUserListener.class) public class SysUser extends BaseEntity { // ... @Schema(description = "用户ID") @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "user_id") private Long userId; // ... @Schema(description = "用户账号") @NotBlank(message = "用户账号不能为空") @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符") @Column(name = "user_name") private String userName; }
2. java 反射 拿到id 和值 作为 更新的 主键
package com.ricoh.srcb.system.service; import com.ricoh.srcb.system.entity.domain.SysMenu; import com.ricoh.srcb.system.framework.web.domain.BaseEntity; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.apache.commons.lang3.ObjectUtils; import javax.persistence.Column; import javax.persistence.EntityManager; import javax.persistence.Id; import javax.persistence.PersistenceContext; import javax.persistence.criteria.*; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.AbstractMap; import java.util.ArrayList; import java.util.List; import java.util.Map; @Service @Slf4j public abstract class GenericService<T extends BaseEntity> { @PersistenceContext private EntityManager entityManager; /** * Updates the given entity by setting non-null fields. * * @param entity The entity to update. * @return The number of rows affected by the update. */ public int baseUpdate(T entity) { CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaUpdate<T> criteriaUpdate = criteriaBuilder.createCriteriaUpdate(entityClass()); Root<T> root = criteriaUpdate.from(entityClass()); Field idField = getIdFieldAndValue(entity).getKey(); Object idValue = getIdFieldAndValue(entity).getValue(); if (ObjectUtils.isEmpty(idValue)) { throw new RuntimeException("jpa update id not null"); } criteriaUpdate.where(criteriaBuilder.equal(root.get(idField.getName()), idValue)); boolean hasFieldsToUpdate = false; Field[] fields = entity.getClass().getDeclaredFields(); for (Field field : fields) { boolean annotationPresent = field.isAnnotationPresent(Column.class); if (!idField.getName().equals(field.getName())&&annotationPresent) { // Exclude the id field try { field.setAccessible(true); Object value = field.get(entity); if (ObjectUtils.isNotEmpty(value)) { criteriaUpdate.set(field.getName(), value); hasFieldsToUpdate = true; } } catch (IllegalAccessException e) { throw new RuntimeException("Error accessing field: " + field.getName(), e); } } } if (!hasFieldsToUpdate) { throw new IllegalArgumentException("No fields to update"); } log.info("update table {} ,sql:{}", entity.getClass().getName(), criteriaUpdate); return entityManager.createQuery(criteriaUpdate).executeUpdate(); } private Map.Entry<Field, Object> getIdFieldAndValue(T entity) { for (Field field : entity.getClass().getDeclaredFields()) { if (field.isAnnotationPresent(Id.class)) { field.setAccessible(true); try { Object value = field.get(entity); return new AbstractMap.SimpleEntry<>(field, value); } catch (IllegalAccessException e) { throw new RuntimeException("Error accessing @Id field.", e); } } } throw new IllegalStateException("No @Id field found in entity class."); } /** * Finds an entity by its ID. * * @param id The ID of the entity to find. * @return The found entity or null if not found. */ /** * Finds entities based on non-null fields of the provided entity. * * @param queryEntity The entity used as a template for query conditions. * @return A list of entities that match the query conditions. */ public List<T> findByCriteria(T queryEntity) { CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery<T> criteriaQuery = criteriaBuilder.createQuery(entityClass()); Root<T> root = criteriaQuery.from(entityClass()); List<Predicate> predicates = new ArrayList<>(); Field[] fields = entityClass().getDeclaredFields(); for (Field field : fields) { try { field.setAccessible(true); Object value = field.get(queryEntity); if (ObjectUtils.isNotEmpty(value)) { predicates.add(criteriaBuilder.equal(root.get(field.getName()), value)); } } catch (IllegalAccessException e) { throw new RuntimeException("Error accessing field: " + field.getName(), e); } } criteriaQuery.where(predicates.toArray(new Predicate[0])); return entityManager.createQuery(criteriaQuery).getResultList(); } private Class<T> entityClass() { Type superClass = getClass().getGenericSuperclass(); if (superClass instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) superClass; Type entityType = parameterizedType.getActualTypeArguments()[0]; if (entityType instanceof Class) { return (Class<T>) entityType; } else { throw new IllegalArgumentException("Expected a class type for the generic parameter but got " + entityType); } } else { throw new IllegalArgumentException("Expected a ParameterizedType but got " + superClass); } } public abstract List<SysMenu> selectMenuList(SysMenu menu, Long userId); }
3.service 进行 继承这个类 进行通用查询和更新
@Service
public class SysMenuServiceImpl extends GenericService<SysMenu> implements ISysMenuService {
@Override
@Transactional
public Boolean updateRole(SysRole role) {
// 修改角色信息
baseUpdate(role);
return insertRoleMenu(role) > 0 ? true : false;
}
}
标签:return,jpa,spring,getName,boot,entity,field,new,import From: https://www.cnblogs.com/hejunhong/p/18254805