V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Braisdom
V2EX  ›  Java

Java ORM 中简洁的关联对象查询和分页查询

  •  
  •   Braisdom ·
    braisdom · 2020-11-28 09:41:51 +08:00 · 3331 次点击
    这是一个创建于 1235 天前的主题,其中的信息可能已经有所发展或是发生改变。

    只需要定义一个 DomainModel

    @DomainModel
    public class Member {
        private String no;
        
        @Queryable
        private String name;
        private Integer gender;
        private String mobile;
        private String otherInfo;
    
        @Relation(relationType = RelationType.HAS_MANY)
        private List<Order> orders;
    }
    

    关联对象查询方法:

    Member.queryAll(Member.HAS_MANY_ORDERS);
    Member.queryByPrimary(1, Member.HAS_MANY_ORDERS);
    Member.queryByName("demo", Member.HAS_MANY_ORDERS);
    

    分页查询:

    Page page = Page.create(0, 10);
    PagedList<Member> members = Member.pagedQueryAll(page, Member.HAS_MANY_ORDERS);
    

    更多请参考: https://github.com/braisdom/ObjectiveSql

    27 条回复    2020-11-29 15:02:53 +08:00
    hantsy
        1
    hantsy  
       2020-11-28 10:55:27 +08:00
    QueryDSL 早实现了。
    wysnylc
        2
    wysnylc  
       2020-11-28 11:12:31 +08:00
    关联查询存在 N+1 问题
    分页查询用 pageHelper
    Braisdom
        3
    Braisdom  
    OP
       2020-11-28 11:33:32 +08:00
    @hantsy 哈哈,我和 QueryDSL 有本质的区别,有必要写个两者的区别,有兴趣看一下

    https://github.com/braisdom/ObjectiveSql 文章的最后
    Braisdom
        4
    Braisdom  
    OP
       2020-11-28 11:34:07 +08:00
    @wysnylc N+1 的问题已经解决了。


    @hantsy 最关键我是不需要写代码的,哈哈
    hantsy
        5
    hantsy  
       2020-11-28 12:04:52 +08:00
    和 JOOQ 呢?
    hantsy
        6
    hantsy  
       2020-11-28 12:05:50 +08:00
    JOOQ 和 QueryDSL 都是可以生成方便 DSL 表达的查询语句代码。
    hantsy
        7
    hantsy  
       2020-11-28 12:09:21 +08:00
    加一个 @DomainModel 把贫血模型,变成 Rich Model 。这个与以前的 Spring Roo 1.x ( Spring 放弃这个项目)类似。https://github.com/hantsy/spring-sandbox/wiki/tao-of-spring-roo
    Braisdom
        8
    Braisdom  
    OP
       2020-11-28 12:12:49 +08:00
    @hantsy

    是的它们两个都可以通过 Java 代码生成 SQL,但他们有致命的缺点。
    1 ) Java 代码的生成需要手动编译,这样的话模型内容变化里,需要手动生成代码。
    2 )算术运算符、比较运算符和逻辑运算都是通过方法的形式实现,这样会使 Java 代码过于复杂

    举个简单的例子:

    SQL 表达式:
    (`T0`.`quantity` > 30) AND `T0`.`sales_at` BETWEEN '2020-10-10 00:00:00' AND '2020-10-30 23:59:59')

    QueryDSL 和 JOOQ 中会是这样的

    exp.and(table.quantity.gt(30), table.salesAt.between("2020-10-10 00:00:00", "2020-10-30 23:59:59")

    而 ObjectiveSQL 中是这样的:

    orderTable.quantity > 30 && orderTable.salesAt.between("2020-10-10 00:00:00", "2020-10-30 23:59:59")

    你能看出区别吗?如果表达式再复杂一点呢?
    Braisdom
        9
    Braisdom  
    OP
       2020-11-28 12:15:42 +08:00
    @hantsy
    贫血模型 与充血模型 本质上不重要,关键对开发来讲,你的效率有没有得到提升,思考问题要从实际出发。

    不需要编写一行额外的代码,就能实现一张表的
    1 )简单基于属性的查询
    2 )关联对象查询
    3 ) Validation
    还有更多...
    Braisdom
        10
    Braisdom  
    OP
       2020-11-28 12:17:34 +08:00
    @hantsy 我在设计 ObjectiveSQL 时,已经忘记了 SQL 的存在,站在 Java 语言的基础上思考,如果通过 Java 语言更方便的查询和分析数据,这是本质
    liununu
        11
    liununu  
       2020-11-28 12:23:47 +08:00 via Android
    @hantsy 加上 DomainModel 的 Annotation 也没有变成充血模型吧,充血的应该是业务逻辑的方法。如果真把 Annotation 加到 Domain Model 上,其实算是把技术框架的实现入侵到了业务。
    Braisdom
        12
    Braisdom  
    OP
       2020-11-28 12:31:24 +08:00   ❤️ 1
    @liununu
    你说法非常正确,讨论到问题的核心了
    大都数业务中,一个 DomainModel 会对应数据库中的一张表,而 DomainModel 也就承担了基础的数据库访问能力,以及围绕该 DomainModel 产生的业务特性。

    ObjectiveSQL 只是动态生成了所有数据库访问的能力,不需要额外编写代码就可以直接使用,减少重复的编码量,提升开发效率。

    至于上面描述的复杂 SQL 的编程,只是在 DomainModel 中进行复杂的业务逻辑处理时所用的特性。

    ObjectiveSQL 和 Spring 一样都是侵入原生的 Java Class,只不过 Spring 更加隐晦,你感觉不到,而 ObjectiveSQL 的侵入更加明显,而且与实际的业务代码进行结合。这就是和 Sping 本质的区别
    hantsy
        13
    hantsy  
       2020-11-28 12:40:42 +08:00   ❤️ 2
    好吧。

    都是使用 Java 5 中的 APT 生成代码,要么修改最终的 Class (如,Lombok ),要么和 JPA 一样另外外生成一些 Java 源文件,再编译成 Class 。我不知道你说的要手动生成什么意思,IDEA,Eclipse 只要 Enable Annotatoins Processor 就可以了。如果脱离 IDE,使用 Maven 都要编译处理。NetBeans 天生支持 Annotation Processor,会自动检测变化。

    如果站在 Java 的角度思考,我会尽量 OOP 思维去编程,选择 JPA 类似的 ORM,而尽可能的去 SQL 化。

    不过写这种工具对 Java 语法树分析,JLS 应该有更深的认识,值得学习。作为 Java 开源项目,我希望:

    1 。全面写单元测试
    2 。添加 Github Actions CI 集成,或者其它 CI
    3 。添加 CodeCoverage 报告,代码质量报告 ,比如挂一个 SonarCloud 集成
    hcymk2
        14
    hcymk2  
       2020-11-28 13:12:31 +08:00
    hcymk2
        15
    hcymk2  
       2020-11-28 13:16:08 +08:00   ❤️ 1
    接触过多种语言 ORM 。相比较 JOOQ 我更接受 ObjectiveSql 的方式。
    php01
        16
    php01  
       2020-11-28 13:43:00 +08:00
    啥时候写 java 的数据操作,能像 php 的 laravel 框架的 orm 一样
    Braisdom
        17
    Braisdom  
    OP
       2020-11-28 14:24:38 +08:00
    @hantsy
    首先,你先要理解为什么要动态生成,动态生成代码的目的是为了解决重复编码的问题,所谓 OOP 也只是站在简洁的代码基础上的。

    OOP 只是一个理论的基础,它无法脱离现实,如果 OOP 会带来太多的重复代码,那么这样的编程也不具备效率。
    编程理论有很多种理解的范式,它可以是一份工作,也可以是一份毕业论文,当然也可以是想象中的世界。

    我的心中没有面向对象,也没有面向过程,更没有所谓的设计模式,我只有让自身的工作变得简单的想法,很淳朴的想法。若干年后,程序员的职业是否存在都是一个未知数...
    Braisdom
        18
    Braisdom  
    OP
       2020-11-28 14:28:51 +08:00
    @hcymk2 感谢认可,往往认可我项目的人,都是经历过各种 ORM 框架的困扰,我经历太多了,实在忍无可忍了,才下定决心搞一个新的,
    VHacker1989
        19
    VHacker1989  
       2020-11-28 14:54:13 +08:00
    分页太啰嗦了,不如 pagehelper 简洁,建议约定由于配置的原则
    Braisdom
        20
    Braisdom  
    OP
       2020-11-28 14:54:29 +08:00
    @php01 PHP 还是我十几年前写过,已经忘记它是个什么样子了,但我看了 laravel 的框架,还是存在很多问题
    1 )模型与模型内的字段,应当是编程中的元素,而不应该是一个字符串
    2 )它的很多元语已经脱离结构化的编程,虽然说每种语言都应有自己的编程元语,但在当然,我们应当遵循前人的命名规范,当然可以超越前人的思想
    3 )它的表达式,还是不够完美,">",”<“ 这类太过怪异
    Braisdom
        21
    Braisdom  
    OP
       2020-11-28 14:55:25 +08:00
    @VHacker1989
    兄弟,我没有任何配置,所谓有 Page 的实例也是业务系统中不可或缺的
    Braisdom
        22
    Braisdom  
    OP
       2020-11-28 15:05:10 +08:00
    @VHacker1989 如果你真用了 MyBatis 的 PageHelpper 你再体验一下 ObjectiveSQL 你会觉得 MyBatis 做的太 Low 了,
    如果你再看一下两者的代码,就觉得 MyBatis PageHelpper 更 Low 了
    wdwwtzy
        23
    wdwwtzy  
       2020-11-28 22:21:03 +08:00
    建议看一下 C#的 entity framework core,应该是各语言 ORM 的天花板了
    Braisdom
        24
    Braisdom  
    OP
       2020-11-29 10:35:08 +08:00
    @wdwwtzy 相信 ObjectiveSQL 将是 ORM 的一个新的巅峰
    beginor
        25
    beginor  
       2020-11-29 14:18:26 +08:00 via Android
    @Braisdom 想在 Java 这颗老树上开新华并不那么容易, 毕竟受限于 Java 陈旧的语法, 伪泛型等等。 很多有能力的大公司都开发新的 JVM 语言了, 比如 scalar,kotlin 等等。

    当然楼主这个项目还是挺不错的, 毕竟开发者最需要灵活的 SQL 生成方式,linq/lambda 表达式可以说是最好的方式了, 比如 .net 平台上的任何一个 orm 都支持 linq/lambda 表达式查询, 否则只有被鄙视的份, 根本不会有人去使用。

    不过我感到奇怪的是, 实现 linq 类似的查询,在 .net 平台上采用的方法是构建表达式树, 然后将表达式树转化为 sql, 中间不需要借助代码生成, 为什么到了 java 这里就必须得生成代码, 还得依赖 ide 插件呢?

    另外, 建议楼主可以多写一些英文的文档, 到国外的社区发表一下, 看看国外的开发者的反应如何。
    Braisdom
        26
    Braisdom  
    OP
       2020-11-29 14:50:16 +08:00
    @beginor 本质上,我也设计过 JVM 的语言,之前命名为 JDS(Java Database Script),但最终发现,所谓的新型的语言还是和传统 Java 语言结合太紧密,所以也就放弃了。还是改造现有的 Java 语言最为实际。

    我觉得 Lambda 不是最优的方法,我的目标是忘记 SQL 的存在,以 Java 编程模型解决数据查询和分析,以过程化的方式解决 SQL 编程的复杂性。我的 github 上有大量老外关注的,我也在尝试在国外的社区推广
    Braisdom
        27
    Braisdom  
    OP
       2020-11-29 15:02:53 +08:00
    @beginor 还有一点,我想阐述一下,不存在什么老树开新花,我的目标是改变传统的 Java 编程模型,Spring 是现在比较流行的编程模型,但我想一步一步改变它,先坐 ORM 开始
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1081 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 18:45 · PVG 02:45 · LAX 11:45 · JFK 14:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.