在 Spring Data Jpa 中使用逻辑删除需做的工作

本文介绍如何在SpringData中实现逻辑删除,通过自定义SimpleJpaRepository以适应逻辑删除的需求,并调整了findByXXX方法以确保查询时能过滤掉已逻辑删除的数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring Data 是个好东西,极大简化了后端dao的操作,只需要在 dao 接口写个 findByXXX 的方法就能自动实现按条件查询这个简直太爽了。

 

不过问题也出现了,我的应用对于数据的操作没有物理删除,全是逻辑删除,也就是每个表都有个字段 deleted,1表示此记录已删除,默认值为 0 。这就与 spring data 提供的模式有冲突了,那剩下的就是:改之。

 

CRUD 操作

对于基础的CRUD 操作搞起来比较简单,按照其官方文档重新实现个 factory-class 就ok了,具体的 repository 类可以继承 org.springframework.data.jpa.repository.support.SimpleJpaRepository 进行修改,不过我为了省事,直接把这个类复制过来然后下手:

 

Java代码  收藏代码
  1. /* 
  2.  * $Id$ 
  3.  */  
  4. package com.someok.common.base.spring.data;  
  5.   
  6. import static org.springframework.data.jpa.repository.query.QueryUtils.DELETE_ALL_QUERY_STRING;  
  7. import static org.springframework.data.jpa.repository.query.QueryUtils.applyAndBind;  
  8. import static org.springframework.data.jpa.repository.query.QueryUtils.getQueryString;  
  9. import static org.springframework.data.jpa.repository.query.QueryUtils.toOrders;  
  10.   
  11. import java.io.Serializable;  
  12. import java.util.ArrayList;  
  13. import java.util.Collections;  
  14. import java.util.List;  
  15.   
  16. import javax.persistence.EntityManager;  
  17. import javax.persistence.LockModeType;  
  18. import javax.persistence.NoResultException;  
  19. import javax.persistence.TypedQuery;  
  20. import javax.persistence.criteria.CriteriaBuilder;  
  21. import javax.persistence.criteria.CriteriaQuery;  
  22. import javax.persistence.criteria.Path;  
  23. import javax.persistence.criteria.Predicate;  
  24. import javax.persistence.criteria.Root;  
  25.   
  26. import org.springframework.dao.EmptyResultDataAccessException;  
  27. import org.springframework.data.domain.Page;  
  28. import org.springframework.data.domain.PageImpl;  
  29. import org.springframework.data.domain.Pageable;  
  30. import org.springframework.data.domain.Sort;  
  31. import org.springframework.data.jpa.domain.Specification;  
  32. import org.springframework.data.jpa.repository.support.JpaEntityInformation;  
  33. import org.springframework.data.jpa.repository.support.JpaEntityInformationSupport;  
  34. import org.springframework.data.jpa.repository.support.LockMetadataProvider;  
  35. import org.springframework.data.jpa.repository.support.SimpleJpaRepository;  
  36. import org.springframework.transaction.annotation.Transactional;  
  37. import org.springframework.util.Assert;  
  38.   
  39. import com.someok.common.base.mvc.BaseDao;  
  40. import com.someok.common.base.mvc.BaseDefaultModel;  
  41. import com.someok.common.utils.StringUtil;  
  42.   
  43. /** 
  44.  * 修改自 
  45.  * {@link org.springframework.data.jpa.repository.support.SimpleJpaRepository}, 
  46.  * 提供逻辑删除功能(logicDelete),为适应这个要求,相关的查询也都做了修改。 
  47.  *  
  48.  * 需要注意的是那些 delete 方法仍然是物理删除,而新增的那些 logic 开头的方法才是逻辑删除, 用时候需要注意这点. 
  49.  *  
  50.  * @author wangjxe 
  51.  *  
  52.  */  
  53. @org.springframework.stereotype.Repository  
  54. @Transactional(readOnly = true)  
  55. public class CustomSimpleJpaRepository<T, ID extends Serializable> implements  
  56.         BaseDao<T, ID> {  
  57.   
  58.     /** 
  59.      * 逻辑删除字段名. 
  60.      */  
  61.     public final static String DELETEED_FIELD = "deleted";  
  62.   
  63.     public static final String COUNT_QUERY_STRING = "select count(%s) from %s x where x.deleted = false";  
  64.     public static final String EXISTS_QUERY_STRING = "select count(%s) from %s x where x.%s = :id and x.deleted = false";  
  65.   
  66.     private final JpaEntityInformation<T, ?> entityInformation;  
  67.     private final EntityManager em;  
  68.     // private final PersistenceProvider provider;  
  69.   
  70.     private LockMetadataProvider lockMetadataProvider;  
  71.   
  72.     /** 
  73.      * Creates a new {@link SimpleJpaRepository} to manage objects of the given 
  74.      * {@link JpaEntityInformation}. 
  75.      *  
  76.      * @param entityInformation 
  77.      *            must not be {@literal null}. 
  78.      * @param entityManager 
  79.      *            must not be {@literal null}. 
  80.      */  
  81.     public CustomSimpleJpaRepository(  
  82.             JpaEntityInformation<T, ?> entityInformation,  
  83.             EntityManager entityManager) {  
  84.   
  85.         Assert.notNull(entityInformation);  
  86.         Assert.notNull(entityManager);  
  87.   
  88.         this.entityInformation = entityInformation;  
  89.         this.em = entityManager;  
  90.         // this.provider = PersistenceProvider.fromEntityManager(entityManager);  
  91.     }  
  92.   
  93.     /** 
  94.      * Creates a new {@link SimpleJpaRepository} to manage objects of the given 
  95.      * domain type. 
  96.      *  
  97.      * @param domainClass 
  98.      *            must not be {@literal null}. 
  99.      * @param em 
  100.      *            must not be {@literal null}. 
  101.      */  
  102.     public CustomSimpleJpaRepository(Class<T> domainClass, EntityManager em) {  
  103.         this(JpaEntityInformationSupport.getMetadata(domainClass, em), em);  
  104.     }  
  105.   
  106.     /** 
  107.      * Configures a custom {@link LockMetadataProvider} to be used to detect 
  108.      * {@link LockModeType}s to be applied to queries. 
  109.      *  
  110.      * @param lockMetadataProvider 
  111.      */  
  112.     public void setLockMetadataProvider(  
  113.             LockMetadataProvider lockMetadataProvider) {  
  114.         this.lockMetadataProvider = lockMetadataProvider;  
  115.     }  
  116.   
  117.     private Class<T> getDomainClass() {  
  118.         return entityInformation.getJavaType();  
  119.     }  
  120.   
  121.     private String getDeleteAllQueryString() {  
  122.         return getQueryString(DELETE_ALL_QUERY_STRING,  
  123.                 entityInformation.getEntityName());  
  124.     }  
  125.   
  126.     private String getCountQueryString() {  
  127.   
  128.         String countQuery = String.format(COUNT_QUERY_STRING,  
  129.                 getCountQueryPlaceholder(), "%s");  
  130.         return getQueryString(countQuery, entityInformation.getEntityName());  
  131.     }  
  132.   
  133.     /* 
  134.      * (non-Javadoc) 
  135.      *  
  136.      * @see org.springframework.data.repository.CrudRepository#delete(java.io. 
  137.      * Serializable) 
  138.      */  
  139.     @Transactional  
  140.     public void delete(ID id) {  
  141.   
  142.         Assert.notNull(id, "The given id must not be null!");  
  143.   
  144.         if (!exists(id)) {  
  145.             throw new EmptyResultDataAccessException(String.format(  
  146.                     "No %s entity with id %s exists!",  
  147.                     entityInformation.getJavaType(), id), 1);  
  148.         }  
  149.   
  150.         delete(findOne(id));  
  151.     }  
  152.   
  153.     /* 
  154.      * (non-Javadoc) 
  155.      *  
  156.      * @see 
  157.      * org.springframework.data.repository.CrudRepository#delete(java.lang.Object 
  158.      * ) 
  159.      */  
  160.     @Transactional  
  161.     public void delete(T entity) {  
  162.   
  163.         Assert.notNull(entity, "The entity must not be null!");  
  164.         em.remove(em.contains(entity) ? entity : em.merge(entity));  
  165.     }  
  166.   
  167.     /* 
  168.      * (non-Javadoc) 
  169.      *  
  170.      * @see 
  171.      * org.springframework.data.repository.CrudRepository#delete(java.lang.Iterable 
  172.      * ) 
  173.      */  
  174.     @Transactional  
  175.     public void delete(Iterable<? extends T> entities) {  
  176.   
  177.         Assert.notNull(entities, "The given Iterable of entities not be null!");  
  178.   
  179.         for (T entity : entities) {  
  180.             delete(entity);  
  181.         }  
  182.     }  
  183.   
  184.     /* 
  185.      * (non-Javadoc) 
  186.      *  
  187.      * @see 
  188.      * org.springframework.data.jpa.repository.JpaRepository#deleteInBatch(java 
  189.      * .lang.Iterable) 
  190.      */  
  191.     @Transactional  
  192.     public void deleteInBatch(Iterable<T> entities) {  
  193.   
  194.         Assert.notNull(entities, "The given Iterable of entities not be null!");  
  195.   
  196.         if (!entities.iterator().hasNext()) {  
  197.             return;  
  198.         }  
  199.   
  200.         applyAndBind(  
  201.                 getQueryString(DELETE_ALL_QUERY_STRING,  
  202.                         entityInformation.getEntityName()), entities, em)  
  203.                 .executeUpdate();  
  204.     }  
  205.   
  206.     /* 
  207.      * (non-Javadoc) 
  208.      *  
  209.      * @see org.springframework.data.repository.Repository#deleteAll() 
  210.      */  
  211.     @Transactional  
  212.     public void deleteAll() {  
  213.   
  214.         for (T element : findAll()) {  
  215.             delete(element);  
  216.         }  
  217.     }  
  218.   
  219.     /* 
  220.      * (non-Javadoc) 
  221.      *  
  222.      * @see 
  223.      * org.springframework.data.jpa.repository.JpaRepository#deleteAllInBatch() 
  224.      */  
  225.     @Transactional  
  226.     public void deleteAllInBatch() {  
  227.         em.createQuery(getDeleteAllQueryString()).executeUpdate();  
  228.     }  
  229.   
  230.     /* 
  231.      * (non-Javadoc) 
  232.      *  
  233.      * @see 
  234.      * org.springframework.data.repository.Repository#readById(java.io.Serializable 
  235.      * ) 
  236.      */  
  237.     public T findOne(ID id) {  
  238.   
  239.         Assert.notNull(id, "The given id must not be null!");  
  240.         return em.find(getDomainClass(), id);  
  241.     }  
  242.   
  243.     /* 
  244.      * (non-Javadoc) 
  245.      *  
  246.      * @see org.springframework.data.repository.CrudRepository#exists(java.io. 
  247.      * Serializable) 
  248.      */  
  249.     public boolean exists(ID id) {  
  250.   
  251.         Assert.notNull(id, "The given id must not be null!");  
  252.   
  253.         if (entityInformation.getIdAttribute() != null) {  
  254.   
  255.             String placeholder = getCountQueryPlaceholder();  
  256.             String entityName = entityInformation.getEntityName();  
  257.             String idAttributeName = entityInformation.getIdAttribute()  
  258.                     .getName();  
  259.             String existsQuery = String.format(EXISTS_QUERY_STRING,  
  260.                     placeholder, entityName, idAttributeName);  
  261.   
  262.             TypedQuery<Long> query = em.createQuery(existsQuery, Long.class);  
  263.             query.setParameter("id", id);  
  264.   
  265.             return query.getSingleResult() == 1;  
  266.         } else {  
  267.             return findOne(id) != null;  
  268.         }  
  269.     }  
  270.   
  271.     /* 
  272.      * (non-Javadoc) 
  273.      *  
  274.      * @see org.springframework.data.jpa.repository.JpaRepository#findAll() 
  275.      */  
  276.     public List<T> findAll() {  
  277.         return getQuery(null, (Sort) null).getResultList();  
  278.     }  
  279.   
  280.     /* 
  281.      * (non-Javadoc) 
  282.      *  
  283.      * @see org.springframework.data.repository.CrudRepository#findAll(ID[]) 
  284.      */  
  285.     public List<T> findAll(Iterable<ID> ids) {  
  286.   
  287.         return getQuery(new Specification<T>() {  
  288.             public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,  
  289.                     CriteriaBuilder cb) {  
  290.                 Path<?> path = root.get(entityInformation.getIdAttribute());  
  291.                 return path.in(cb.parameter(List.class"ids"));  
  292.             }  
  293.         }, (Sort) null).setParameter("ids", ids).getResultList();  
  294.     }  
  295.   
  296.     /* 
  297.      * (non-Javadoc) 
  298.      *  
  299.      * @see org.springframework.data.jpa.repository.JpaRepository#findAll(org. 
  300.      * springframework.data.domain.Sort) 
  301.      */  
  302.     public List<T> findAll(Sort sort) {  
  303.         return getQuery(null, sort).getResultList();  
  304.     }  
  305.   
  306.     /* 
  307.      * (non-Javadoc) 
  308.      *  
  309.      * @see 
  310.      * org.springframework.data.repository.PagingAndSortingRepository#findAll 
  311.      * (org.springframework.data.domain.Pageable) 
  312.      */  
  313.     public Page<T> findAll(Pageable pageable) {  
  314.   
  315.         if (null == pageable) {  
  316.             return new PageImpl<T>(findAll());  
  317.         }  
  318.   
  319.         return findAll(null, pageable);  
  320.     }  
  321.   
  322.     /* 
  323.      * (non-Javadoc) 
  324.      *  
  325.      * @see 
  326.      * org.springframework.data.jpa.repository.JpaSpecificationExecutor#findOne 
  327.      * (org.springframework.data.jpa.domain.Specification) 
  328.      */  
  329.     public T findOne(Specification<T> spec) {  
  330.   
  331.         try {  
  332.             return getQuery(spec, (Sort) null).getSingleResult();  
  333.         } catch (NoResultException e) {  
  334.             return null;  
  335.         }  
  336.     }  
  337.   
  338.     /* 
  339.      * (non-Javadoc) 
  340.      *  
  341.      * @see 
  342.      * org.springframework.data.jpa.repository.JpaSpecificationExecutor#findAll 
  343.      * (org.springframework.data.jpa.domain.Specification) 
  344.      */  
  345.     public List<T> findAll(Specification<T> spec) {  
  346.         return getQuery(spec, (Sort) null).getResultList();  
  347.     }  
  348.   
  349.     /* 
  350.      * (non-Javadoc) 
  351.      *  
  352.      * @see 
  353.      * org.springframework.data.jpa.repository.JpaSpecificationExecutor#findAll 
  354.      * (org.springframework.data.jpa.domain.Specification, 
  355.      * org.springframework.data.domain.Pageable) 
  356.      */  
  357.     public Page<T> findAll(Specification<T> spec, Pageable pageable) {  
  358.   
  359.         TypedQuery<T> query = getQuery(spec, pageable);  
  360.         return pageable == null ? new PageImpl<T>(query.getResultList())  
  361.                 : readPage(query, pageable, spec);  
  362.     }  
  363.   
  364.     /* 
  365.      * (non-Javadoc) 
  366.      *  
  367.      * @see 
  368.      * org.springframework.data.jpa.repository.JpaSpecificationExecutor#findAll 
  369.      * (org.springframework.data.jpa.domain.Specification, 
  370.      * org.springframework.data.domain.Sort) 
  371.      */  
  372.     public List<T> findAll(Specification<T> spec, Sort sort) {  
  373.   
  374.         return getQuery(spec, sort).getResultList();  
  375.     }  
  376.   
  377.     /* 
  378.      * (non-Javadoc) 
  379.      *  
  380.      * @see org.springframework.data.repository.CrudRepository#count() 
  381.      */  
  382.     public long count() {  
  383.         return em.createQuery(getCountQueryString(), Long.class)  
  384.                 .getSingleResult();  
  385.     }  
  386.   
  387.     /* 
  388.      * (non-Javadoc) 
  389.      *  
  390.      * @see 
  391.      * org.springframework.data.jpa.repository.JpaSpecificationExecutor#count 
  392.      * (org.springframework.data.jpa.domain.Specification) 
  393.      */  
  394.     public long count(Specification<T> spec) {  
  395.   
  396.         return getCountQuery(spec).getSingleResult();  
  397.     }  
  398.   
  399.     /* 
  400.      * (non-Javadoc) 
  401.      *  
  402.      * @see 
  403.      * org.springframework.data.repository.CrudRepository#save(java.lang.Object) 
  404.      */  
  405.     @Transactional  
  406.     public <S extends T> S save(S entity) {  
  407.   
  408.         if (entityInformation.isNew(entity)) {  
  409.             em.persist(entity);  
  410.             return entity;  
  411.         } else {  
  412.             return em.merge(entity);  
  413.         }  
  414.     }  
  415.   
  416.     /* 
  417.      * (non-Javadoc) 
  418.      *  
  419.      * @see 
  420.      * org.springframework.data.jpa.repository.JpaRepository#saveAndFlush(java 
  421.      * .lang.Object) 
  422.      */  
  423.     @Transactional  
  424.     public T saveAndFlush(T entity) {  
  425.   
  426.         T result = save(entity);  
  427.         flush();  
  428.   
  429.         return result;  
  430.     }  
  431.   
  432.     /* 
  433.      * (non-Javadoc) 
  434.      *  
  435.      * @see 
  436.      * org.springframework.data.jpa.repository.JpaRepository#save(java.lang. 
  437.      * Iterable) 
  438.      */  
  439.     @Transactional  
  440.     public <S extends T> List<S> save(Iterable<S> entities) {  
  441.   
  442.         List<S> result = new ArrayList<S>();  
  443.   
  444.         if (entities == null) {  
  445.             return result;  
  446.         }  
  447.   
  448.         for (S entity : entities) {  
  449.             result.add(save(entity));  
  450.         }  
  451.   
  452.         return result;  
  453.     }  
  454.   
  455.     /* 
  456.      * (non-Javadoc) 
  457.      *  
  458.      * @see org.springframework.data.jpa.repository.JpaRepository#flush() 
  459.      */  
  460.     @Transactional  
  461.     public void flush() {  
  462.   
  463.         em.flush();  
  464.     }  
  465.   
  466.     /** 
  467.      * Reads the given {@link TypedQuery} into a {@link Page} applying the given 
  468.      * {@link Pageable} and {@link Specification}. 
  469.      *  
  470.      * @param query 
  471.      *            must not be {@literal null}. 
  472.      * @param spec 
  473.      *            can be {@literal null}. 
  474.      * @param pageable 
  475.      *            can be {@literal null}. 
  476.      * @return 
  477.      */  
  478.     private Page<T> readPage(TypedQuery<T> query, Pageable pageable,  
  479.             Specification<T> spec) {  
  480.   
  481.         query.setFirstResult(pageable.getOffset());  
  482.         query.setMaxResults(pageable.getPageSize());  
  483.   
  484.         Long total = getCountQuery(spec).getSingleResult();  
  485.         List<T> content = total > pageable.getOffset() ? query.getResultList()  
  486.                 : Collections.<T> emptyList();  
  487.   
  488.         return new PageImpl<T>(content, pageable, total);  
  489.     }  
  490.   
  491.     /** 
  492.      * Creates a new {@link TypedQuery} from the given {@link Specification}. 
  493.      *  
  494.      * @param spec 
  495.      *            can be {@literal null}. 
  496.      * @param pageable 
  497.      *            can be {@literal null}. 
  498.      * @return 
  499.      */  
  500.     private TypedQuery<T> getQuery(Specification<T> spec, Pageable pageable) {  
  501.   
  502.         Sort sort = pageable == null ? null : pageable.getSort();  
  503.         return getQuery(spec, sort);  
  504.     }  
  505.   
  506.     /** 
  507.      * Creates a {@link TypedQuery} for the given {@link Specification} and 
  508.      * {@link Sort}. 
  509.      *  
  510.      * @param spec 
  511.      *            can be {@literal null}. 
  512.      * @param sort 
  513.      *            can be {@literal null}. 
  514.      * @return 
  515.      */  
  516.     private TypedQuery<T> getQuery(Specification<T> spec, Sort sort) {  
  517.   
  518.         CriteriaBuilder builder = em.getCriteriaBuilder();  
  519.         CriteriaQuery<T> query = builder.createQuery(getDomainClass());  
  520.   
  521.         Root<T> root = applySpecificationToCriteria(spec, query);  
  522.         query.select(root);  
  523.   
  524.         if (sort != null) {  
  525.             query.orderBy(toOrders(sort, root, builder));  
  526.         }  
  527.   
  528.         return applyLockMode(em.createQuery(query));  
  529.     }  
  530.   
  531.     /** 
  532.      * Creates a new count query for the given {@link Specification}. 
  533.      *  
  534.      * @param spec 
  535.      *            can be {@literal null}. 
  536.      * @return 
  537.      */  
  538.     private TypedQuery<Long> getCountQuery(Specification<T> spec) {  
  539.   
  540.         CriteriaBuilder builder = em.getCriteriaBuilder();  
  541.         CriteriaQuery<Long> query = builder.createQuery(Long.class);  
  542.   
  543.         Root<T> root = applySpecificationToCriteria(spec, query);  
  544.         query.select(builder.count(root));  
  545.   
  546.         return em.createQuery(query);  
  547.     }  
  548.   
  549.     /** 
  550.      * Applies the given {@link Specification} to the given 
  551.      * {@link CriteriaQuery}. 
  552.      *  
  553.      * @param spec 
  554.      *            can be {@literal null}. 
  555.      * @param query 
  556.      *            must not be {@literal null}. 
  557.      * @return 
  558.      */  
  559.     private <S> Root<T> applySpecificationToCriteria(Specification<T> spec,  
  560.             CriteriaQuery<S> query) {  
  561.   
  562.         Assert.notNull(query);  
  563.         Root<T> root = query.from(getDomainClass());  
  564.   
  565.         CriteriaBuilder builder = em.getCriteriaBuilder();  
  566.   
  567.         // 增加了删除条件判断,从而将被逻辑删除的数据过滤掉  
  568.         Predicate deletedPredicate = null;  
  569.         if (BaseDefaultModel.class.isAssignableFrom(getDomainClass())) {  
  570.             Path<Boolean> deletedPath = root.<Boolean> get(DELETEED_FIELD);  
  571.             deletedPredicate = builder.isFalse(deletedPath);  
  572.         }  
  573.           
  574.         if (spec == null) {  
  575.             // 没有其它条件的时候只判断deleted字段  
  576.             query.where(deletedPredicate);  
  577.               
  578.             return root;  
  579.         }  
  580.           
  581.         Predicate predicate = spec.toPredicate(root, query, builder);  
  582.   
  583.         if (predicate != null) {  
  584.             // 存在其它条件的时候还需要组合一下 deleted 条件  
  585.             if (null != deletedPredicate) {  
  586.                 predicate = builder.and(predicate, deletedPredicate);  
  587.             }  
  588.             query.where(predicate);  
  589.         }  
  590.   
  591.         return root;  
  592.     }  
  593.   
  594.     private TypedQuery<T> applyLockMode(TypedQuery<T> query) {  
  595.   
  596.         LockModeType type = lockMetadataProvider == null ? null  
  597.                 : lockMetadataProvider.getLockModeType();  
  598.         return type == null ? query : query.setLockMode(type);  
  599.     }  
  600.   
  601.     /* 
  602.      * (non-Javadoc) 
  603.      *  
  604.      * @see com.someok.common.base.mvc.BaseDao#logicDelete(java.io.Serializable) 
  605.      */  
  606.     @Override  
  607.     public void logicDelete(ID id) {  
  608.         T entity = findOne(id);  
  609.         if (null == entity || !(entity instanceof BaseDefaultModel)) {  
  610.             return;  
  611.         }  
  612.         BaseDefaultModel model = (BaseDefaultModel) entity;  
  613.         model.setDeleted(true);  
  614.   
  615.         this.em.merge(model);  
  616.     }  
  617.   
  618.     /* 
  619.      * (non-Javadoc) 
  620.      *  
  621.      * @see com.someok.common.base.mvc.BaseDao#logicDelete(java.lang.Object) 
  622.      */  
  623.     @Override  
  624.     public void logicDelete(T entity) {  
  625.         if (null == entity || !(entity instanceof BaseDefaultModel)) {  
  626.             return;  
  627.         }  
  628.   
  629.         BaseDefaultModel model = (BaseDefaultModel) entity;  
  630.         model.setDeleted(true);  
  631.   
  632.         if (StringUtil.isBlank(model.getId())) {  
  633.             em.persist(model);  
  634.         } else {  
  635.             em.merge(model);  
  636.         }  
  637.   
  638.     }  
  639.   
  640.     /* 
  641.      * (non-Javadoc) 
  642.      *  
  643.      * @see com.someok.common.base.mvc.BaseDao#logicDelete(java.lang.Iterable) 
  644.      */  
  645.     @Override  
  646.     public void logicDelete(Iterable<? extends T> entities) {  
  647.         if (null == entities) {  
  648.             return;  
  649.         }  
  650.   
  651.         for (T entity : entities) {  
  652.             logicDelete(entity);  
  653.         }  
  654.     }  
  655.   
  656.     protected String getCountQueryPlaceholder() {  
  657.   
  658.         return "x";  
  659.     }  
  660. }  

 

 主要的改动是 applySpecificationToCriteria 方法,与 SimpleJpaRepository 比对下就知道改了啥了。

 

findByXXX 操作

CURD 的修改还是比较简单的,不过那些根据接口方法自动实现查询修改起来就比较麻烦了。当然,不做任何修改也可以用,只需要在dao接口的方法上面加个 @Query 就行了,但是这样就需要写大量的jpql了,与采用 spring data的原意不符,咱用这玩意目的不就是为了个简单嘛。

 

本来的想法是继承某些类来对需要调整的方法重新实现就ok了,可惜spring data 这块的实现有点太封闭了,多个类没有 public,只能包内可见,更多的需要的方法只提供了 private 属性。没办法,只好把 org.springframework.data.jpa.repository.query 包内的代码都拷贝过来,其实真正需要改动的地方只有一处:

 

com.someok.common.base.spring.data.query.JpaQueryCreator.complete(Predicate, Sort, CriteriaQuery<Object>, CriteriaBuilder, Root<?>)

 

具体修改方法如下:

 

Java代码  收藏代码
  1. protected CriteriaQuery<Object> complete(Predicate predicate, Sort sort,  
  2.         CriteriaQuery<Object> query, CriteriaBuilder builder, Root<?> root) {  
  3.       
  4.     // 增加了删除条件判断,从而将被逻辑删除的数据过滤掉  
  5.     Predicate deletedPredicate = null;  
  6.     if (BaseDefaultModel.class.isAssignableFrom(this.domainClass)) {  
  7.         Path<Boolean> deletedPath = root.<Boolean> get(CustomSimpleJpaRepository.DELETEED_FIELD);  
  8.         deletedPredicate = builder.isFalse(deletedPath);  
  9.     }  
  10.     // 在原有条件基础上组合 deleted 条件  
  11.     if (null != deletedPredicate) {  
  12.         predicate = builder.and(predicate, deletedPredicate);  
  13.     }  
  14.       
  15.     return this.query.select(root).where(predicate)  
  16.             .orderBy(QueryUtils.toOrders(sort, root, builder));  
  17. }  
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值