关于 Spring data jpa 写原生 sql 的问题

2018-07-06 20:42:06 +08:00
 tamer

官网示例中的 @Query(nativeQuery=true) 原生 sql 语句都是

select * ....

, 结果自己用发现, select 部分字段的话, 缺失的字段会被抛出异常:... Column xxx not found.

比如 User 包含 id 和 name, 如果我只 select id from ...., 就会报错. 然后 gg

好不容易从 mybatis 切换到 data jpa, 结果最想要的功能没法用,

stack, 百度 都找不到解决方案, 是 jpa 太小众了, 还是我搜索姿势不对....

要是放弃了, 实在不甘心啊...

有没有也遇到过此问题的道友, 抱拳了 老铁




9094 次点击
所在节点    Java
50 条回复
WispZhan
2018-07-06 22:25:42 +08:00
你用错了。不是你这样用。repository 是针对 entity 的操作。看看 ddd 的设计思想在用 jpa。你会发现,你之前压根就没理解 jpa 的使用场景。

你的 repository 是针对你那个 select * 的 entity 封装的。你要查询部分字段那就重做一个 entity 绑定到你需要的表上。可以理解为做了一个 view。
ke1e
2018-07-07 00:11:06 +08:00
搭车问下 jpa 建索引如何建倒叙索引?想给时间字段建立倒叙索引
wdlth
2018-07-07 00:11:59 +08:00
你需要用投影
mmdsun
2018-07-07 00:57:33 +08:00
告诉个黑科技。如果是 hql 用 new 包名.类名(构造函数)直接获取投影对象。原生 SQL 要写注解配置 mapper。 @SqlResultSetMappings 用列或构造函数映射类
ZSeptember
2018-07-07 02:40:19 +08:00
querydsl
kevinhwang
2018-07-07 08:03:47 +08:00
jpa 也就是做做简单的应用,过度强调 orm 性能和可维护性差。抛开性能讲可维护性,你能理解其他的程序员往你的 entity 加各种字段吗?
mgcnrx11
2018-07-07 08:22:26 +08:00
caotian
2018-07-07 09:10:47 +08:00
弄个 Interface 比如叫 UserLite, 只有一个方法 getId(), 然后查询那里返回值用 List<UserLite>, 再 select id 就不会出错了
letitbesqzr
2018-07-07 09:27:28 +08:00
querydsl 试试
srx1982
2018-07-07 10:25:15 +08:00
你看看实体上的字段是不是标了 @NotNull
q397064399
2018-07-07 11:00:56 +08:00
JPA 是针对聚合实体的,,你那种 不要一部分字段. 我很难理解. , 你要精确控制这数据库这一小段 IO 的话
就应该另外再建个实体 映射到同一张表上。而且从仓储层拿出来的对象 是不完整的话 也违反了最小惊讶原则,
后面谁调你接口 一不小心就弄了 NPE 很尴尬,数据库都是不提倡使用 NULL 值的,

如果只是取一部分数据,这个对象不用修改,那应该建模为值对象而不是实体。
另外用 JPA 最好还是了解下 实体 聚合 值对象,JPA 就是为这玩意设计的。
q397064399
2018-07-07 11:04:29 +08:00
另外用 JPA 就应该从 SQL 中跳出来,关注实体建模, 很多时候都是反模式
yzmm
2018-07-07 11:15:03 +08:00
自定义 Repository 就可以了
zxyroy
2018-07-07 11:34:03 +08:00
如果你只 select id,返回值应该是 id,否则要给返回类设构造器。另外 JQL 是支持 new class 的
dbpe
2018-07-07 11:40:12 +08:00
用 jpa 就不要用原生 sql 了。。另外试下 querydsl

PS:学到了楼上的一些方法了
ren2881971
2018-07-07 12:58:51 +08:00
自己定义 factory-class 然后写一个 baseRepository 在里面用 EntityManager 就可以直接写原生 sql 了,然后撸起袖子就是干。
搜索关键词 jpa:repositories、factory-class、JpaRepositoryFactoryBean、JpaRepositoryFactory。
ps:谁开发后台只用 select * 啊。 开玩笑。。
ren2881971
2018-07-07 13:03:07 +08:00
<jpa:repositories base-package="com.jit.ota4.*.*.repository" repository-impl-postfix="Impl" factory-class="com.jit.ota4.basic.repository.BaseRepositoryFactoryBean" entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager"/>


public class BaseRepositoryFactoryBean<R extends JpaRepository<S, ID>, S, ID extends Serializable>
extends JpaRepositoryFactoryBean<R, S, ID>{
@Override
protected RepositoryFactorySupport createRepositoryFactory(EntityManager e) {
return new BaseRepositoryFactory(e);
}
}


public class BaseRepositoryFactory<S,ID extends Serializable> extends JpaRepositoryFactory {
public BaseRepositoryFactory(EntityManager entityManager) {
super(entityManager);
}

@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return BaseRepository.class;
}

@Override
protected <T, ID extends Serializable> SimpleJpaRepository<?, ?> getTargetRepository(RepositoryInformation information, EntityManager entityManager) {
return new BaseRepositoryImpl(information.getDomainType(), entityManager);
}
}


public interface BaseRepository<T,ID extends Serializable> extends JpaRepository<T,ID>,JpaSpecificationExecutor<T> {


/**
* @param sql 原生 sql 语句
* @param param 动态执行参数 type:List
* @return 返回执行的结果集条数
*/
public int executeUpdateBySQL(String sql,List<Object> param);
/**
* @param sql 原生 sql 语句
* @param param 动态执行参数 type:Map
* @return 返回执行的结果集条数
*/
public int executeUpdateBySQL(String sql,Map<String,Object> param);
/**
* @param hql hql 语句
* @param param 动态执行参数 type:List
* @return 返回执行的结果集条数
*/
public int executeUpdateByHql(String hql,List<Object> param);
/**
* @param hql hql 语句
* @param param 动态执行参数 type:Map
* @return 返回执行的结果集条数
*/
public int executeUpdateByHql(String hql,Map<String,Object> param);

/**
* @param hql hql 语句
* @param param 动态查询参数 type:List
* @param t 单实例类型
* @return 单实例结果集
*/
public List<T> findByHql(String hql,List<Object> param,Class<T> t);

/**
* @param hql hql 语句
* @param param 动态查询参数 type:List
* @param t 单实例类型
* @param pageNo 页码数
* @param pageSize 每页条数
* @return 单实例结果集
*/
public List<T> findByHqlWithPage(String hql,List<Object> param,Class<T> t,int pageNo,int pageSize);

/**
* @param hql hql 语句
* @param param 动态查询参数 type:List
* @return 自定义字段返回结果集
*/
public List<Object[]> findByHql(String hql,List<Object> param);

/**
* @param hql hql 语句
* @param param 动态查询参数 type:List
* @param pageNo 页码数
* @param pageSize 每页条数
* @return 自定义字段返回结果集
*/
public List<Object[]> findByHqlWithPage(String hql,List<Object> param,int pageNo,int pageSize);

/**
* @param sql 原生 sql 语句
* @param param 动态查询参数 type:List
* @return 执行原生 sql 返回结果集
*/
public List<Object[]> findBySQL(String sql,List<Object> param);

/**
* @param sql 原生 sql 语句
* @param param 动态查询参数 type:List
* @param pageNo 页码数
* @param pageSize 每页条数
* @return
*/
public List<Object[]> findBySQLWithPage(String sql,List<Object> param ,int pageNo,int pageSize);


}
ren2881971
2018-07-07 13:04:14 +08:00
糟糕 没排版。。。
dbpe
2018-07-07 13:29:36 +08:00
@ren2881971 贴个 github 的地址把。。
tamer
2018-07-07 13:50:19 +08:00
@ren2881971 感谢 , 主要是被 jpa 的方法名称推断惊艳到了, 连自动生成语句都帮程序员解决了所以就想用用, 实际除了最简单的 select 语句外, 我个人都基本倾向写原生 sql, 所有有这个问题

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/468764

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX