自定义JPA仓库findByName方法因无name属性实体启动报错
问题解决方案
问题根源
Spring Data JPA在应用启动阶段会预解析所有Repository接口中的查询方法(包括标注了@Query的自定义方法),不管你在Service层是否调用该方法。你的ProjectContacts实体没有name属性,但它的Repository继承了包含findByName(带有固定JPQL查询)的MappedTypeRepository,所以JPA尝试为ProjectContacts生成查询时,会找不到name属性,抛出解析异常。
可行解决方案
方案一:拆分自定义Repository接口(推荐)
将通用方法和带name属性依赖的方法拆分为不同的接口,让对应的实体Repository按需继承:
- 修改基础通用Repository
只保留所有实体都适用的方法:
@NoRepositoryBean public interface MappedTypeRepository<T extends BaseEntity> extends JpaRepository<T, Long> { @Modifying @Query(value = "delete from #{#entityName} u where u.id = ?1") int customDeleteById(Long id); }
- 新建针对带
name属性实体的Repository
单独封装findByName方法:
@NoRepositoryBean public interface NamedEntityRepository<T extends BaseEntity> extends MappedTypeRepository<T> { @Query(value = "select t from #{#entityName} t where t.name = ?1") T findByName(String name); }
- 调整各实体Repository的继承关系
- 有
name属性的Project对应的Repository继承NamedEntityRepository:
public interface ProjectRepository extends NamedEntityRepository<Project> { }
- 无
name属性的ProjectContacts对应的Repository只继承MappedTypeRepository:
public interface ProjectContactsRepository extends MappedTypeRepository<ProjectContacts> { }
这样启动时,JPA只会为继承了NamedEntityRepository的Repository解析findByName方法,从根源上避免了无name属性实体的查询解析错误。
方案二:Service层动态判断实体属性(配合接口拆分使用)
如果需要在统一的Service接口中保留findByName方法,可以在实现类中先判断当前实体是否具备name属性,再决定是否执行查询:
@Override public ProjectContacts findByName(ProjectGenericForm projectGenericForm) { // 检查实体是否有name属性 try { ProjectContacts.class.getDeclaredField("name"); return repository.findByName(projectGenericForm.getName()); } catch (NoSuchFieldException e) { return null; } }
注意:这个方案必须配合方案一使用,否则Repository层的findByName方法仍然会在启动时被解析,导致报错。
内容的提问来源于stack exchange,提问作者golgered
相关产品推荐
相关产品推荐

