官网示例中的 @Query(nativeQuery=true) 原生 sql 语句都是
select * ....
, 结果自己用发现, select 部分字段的话, 缺失的字段会被抛出异常:... Column xxx not found.
比如 User 包含 id 和 name, 如果我只 select id from ...., 就会报错. 然后 gg
好不容易从 mybatis 切换到 data jpa, 结果最想要的功能没法用,
stack, 百度 都找不到解决方案, 是 jpa 太小众了, 还是我搜索姿势不对....
要是放弃了, 实在不甘心啊...
有没有也遇到过此问题的道友, 抱拳了 老铁
2
AltairT 2018-07-06 20:44:58 +08:00 via iPhone
关注一下 感觉以后是主流技术了
|
3
airfling 2018-07-06 20:49:58 +08:00 via Android
部分字段只,如果只是一个 id 你可以用 list<idtype>,多的话可以用 list<map>
|
5
Sharuru 2018-07-06 20:55:20 +08:00 via Android
通常是映射的结果集不正确。
另外,JPA 应用一般都是选择实体,通过 Stream 取得自己需要的列。 |
6
tamer OP @shalk 不行, 版本: Maven: org.springframework.data:spring-data-jpa:2.0.8.RELEASE
|
7
tamer OP @Sharuru 官网给出的例子只有 select *, 如果我把所有列都放到 select 语句中就可以成功执行, 但如果缺少某某列, 就会报错,
select user_id from : xx select user_id , username from : √√ 所以可以判断映射的字段是匹配的 |
8
lhx2008 2018-07-06 21:04:21 +08:00 via Android
可以返回一个 int 值再自己装?不知道有什么安全性考虑
|
9
tamer OP @airfling map 确实可以映射, 但是除了直接从库中返回给前端的请求外, 涉及到对 User 的操作, map 就很蓝瘦了呀
|
10
tamer OP @lhx2008 如果所有原生 sql 都必须这样手动封装一次....... 那 jpa 提供的一些蝇头小利真的被 mybatis 完爆啦
|
12
lhx2008 2018-07-06 21:12:09 +08:00
我猜可能是如果有关联对象,会造成很严重的问题
|
13
tamer OP @lhx2008 对于 json 字段, 取的话, 如果每次都必须强制获取全部, 还是很可怕的, 如果解决不了, 我还是只有换回 mybatis 啦
|
14
lhx2008 2018-07-06 21:13:41 +08:00
或者你重新封装一个类,只有 id,然后再让真正的 user 继承这个类,但是调用的时候也只能调用那个父类了
|
15
chocotan 2018-07-06 21:13:49 +08:00 1
select 部分字段 返回值改成 List<Object[]>
既然都是原生 sql 的话那用 jpa 的意义何在...... |
16
lhx2008 2018-07-06 21:15:03 +08:00
|
18
tamer OP @lhx2008 一般情况下, 对于有的属性 实体类则被赋值, 没有的属性自动置为 null, 这不是 orm 框架应该做的吗
Hibernate 都可以自动映射, jpa 封装了 Hibernate 居然就不支持了... |
19
tamer OP @chocotan orm 自动映射的规则不是只要字段名一致, 有值就赋值, 没有值则为 NULL 吗? 现在 jpa 强制要求实体类每一个属性都必须有值, 这才是奇怪的地方把, Hibernate 和 Mybatis 都不是这样吧
|
20
sagaxu 2018-07-06 22:07:35 +08:00 via Android 1
jpa 的工作方式不同,你只能返回 List<Object[]>或者自己定义一个新类型。连返回 map 都不行。
|
21
WispZhan 2018-07-06 22:25:42 +08:00 via Android 1
你用错了。不是你这样用。repository 是针对 entity 的操作。看看 ddd 的设计思想在用 jpa。你会发现,你之前压根就没理解 jpa 的使用场景。
你的 repository 是针对你那个 select * 的 entity 封装的。你要查询部分字段那就重做一个 entity 绑定到你需要的表上。可以理解为做了一个 view。 |
22
ke1e 2018-07-07 00:11:06 +08:00 via Android
搭车问下 jpa 建索引如何建倒叙索引?想给时间字段建立倒叙索引
|
23
wdlth 2018-07-07 00:11:59 +08:00
你需要用投影
|
24
mmdsun 2018-07-07 00:57:33 +08:00 via Android
告诉个黑科技。如果是 hql 用 new 包名.类名(构造函数)直接获取投影对象。原生 SQL 要写注解配置 mapper。 @SqlResultSetMappings 用列或构造函数映射类
|
25
ZSeptember 2018-07-07 02:40:19 +08:00 via Android
querydsl
|
26
kevinhwang 2018-07-07 08:03:47 +08:00 via Android
jpa 也就是做做简单的应用,过度强调 orm 性能和可维护性差。抛开性能讲可维护性,你能理解其他的程序员往你的 entity 加各种字段吗?
|
27
mgcnrx11 2018-07-07 08:22:26 +08:00
|
28
caotian 2018-07-07 09:10:47 +08:00
弄个 Interface 比如叫 UserLite, 只有一个方法 getId(), 然后查询那里返回值用 List<UserLite>, 再 select id 就不会出错了
|
29
letitbesqzr 2018-07-07 09:27:28 +08:00
querydsl 试试
|
31
q397064399 2018-07-07 11:00:56 +08:00 1
JPA 是针对聚合实体的,,你那种 不要一部分字段. 我很难理解. , 你要精确控制这数据库这一小段 IO 的话
就应该另外再建个实体 映射到同一张表上。而且从仓储层拿出来的对象 是不完整的话 也违反了最小惊讶原则, 后面谁调你接口 一不小心就弄了 NPE 很尴尬,数据库都是不提倡使用 NULL 值的, 如果只是取一部分数据,这个对象不用修改,那应该建模为值对象而不是实体。 另外用 JPA 最好还是了解下 实体 聚合 值对象,JPA 就是为这玩意设计的。 |
32
q397064399 2018-07-07 11:04:29 +08:00
另外用 JPA 就应该从 SQL 中跳出来,关注实体建模, 很多时候都是反模式
|
33
yzmm 2018-07-07 11:15:03 +08:00
自定义 Repository 就可以了
|
34
zxyroy 2018-07-07 11:34:03 +08:00
如果你只 select id,返回值应该是 id,否则要给返回类设构造器。另外 JQL 是支持 new class 的
|
35
dbpe 2018-07-07 11:40:12 +08:00
用 jpa 就不要用原生 sql 了。。另外试下 querydsl
PS:学到了楼上的一些方法了 |
36
ren2881971 2018-07-07 12:58:51 +08:00
自己定义 factory-class 然后写一个 baseRepository 在里面用 EntityManager 就可以直接写原生 sql 了,然后撸起袖子就是干。
搜索关键词 jpa:repositories、factory-class、JpaRepositoryFactoryBean、JpaRepositoryFactory。 ps:谁开发后台只用 select * 啊。 开玩笑。。 |
37
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); } |
38
ren2881971 2018-07-07 13:04:14 +08:00
糟糕 没排版。。。
|
39
dbpe 2018-07-07 13:29:36 +08:00
@ren2881971 贴个 github 的地址把。。
|
40
tamer OP @ren2881971 感谢 , 主要是被 jpa 的方法名称推断惊艳到了, 连自动生成语句都帮程序员解决了所以就想用用, 实际除了最简单的 select 语句外, 我个人都基本倾向写原生 sql, 所有有这个问题
|
41
ren2881971 2018-07-07 14:26:18 +08:00
@dbpe https://github.com/ren2881971/spring4mvc-jpa-demo 好几年前搭建的。。。。
|
42
ren2881971 2018-07-07 14:27:45 +08:00
@tamer 估计是你用 mybatis 用习惯了~ 如果一直用 hibernate 的话 没什么感觉~
|
43
nicevar 2018-07-07 17:52:27 +08:00
配置一个 JpaTransactionManager 获取 EntityManager 直接操作原生 sql
|
44
beginor 2018-07-07 18:01:01 +08:00 via Android
JPA 可以认为就是 Hibernate, 我在 .Net 上用的是 NHibernate, 也有类似这样的需求, 复杂的查询用 SQL 解决, 在 .Net 下有现成的轮子 Dapper https://github.com/StackExchange/Dapper,Java 上应该也有类似 Dapper 的轮子吧?
|
45
beginor 2018-07-07 18:03:13 +08:00 via Android
|
46
a812159920 2018-07-07 20:52:25 +08:00
EntityManager API 提供了创建 Query 实例以执行原生 SQL 语句的 createNativeQuery 方法。
链接: https://blog.csdn.net/opera95/article/details/78207416 不谢 |
47
mmdsun 2018-07-08 00:31:40 +08:00 via Android
@a812159920 这个原生 SQL 查询非 select * 返回的是 list<object[]>感觉好麻烦。不能直接返回 list<user>,然后没有查的字段返回 null 么。
|
49
a812159920 2018-07-08 14:29:41 +08:00
|
50
reAsOn 2018-07-09 09:57:12 +08:00
@ke1e 看你用什么版本的数据库了,和 jpa 关系不大,如果是新的 比如 mysql 8 可以直接建倒序的索引,如果比较老,可以用虚拟列,把时间 neg 一遍然后建普通的正序索引
|