{"id":26730342,"url":"https://github.com/paganini2008/easyjpa","last_synced_at":"2025-09-12T00:12:31.981Z","repository":{"id":57721981,"uuid":"376725311","full_name":"paganini2008/easyjpa","owner":"paganini2008","description":"EasyJPA elegantly streamlines JPA's Criteria API with a fully Lambda-expression-based and developer-friendly API, making dynamic queries both intuitive and efficient. It significantly reduces SQL/JPQL complexity, accelerates development, and improves code readability.","archived":false,"fork":false,"pushed_at":"2025-03-26T06:50:31.000Z","size":121,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-29T06:57:03.268Z","etag":null,"topics":["hibernate-jpa","jpa-persistence-applications","orm-library","spring-boot","springboot-jpa"],"latest_commit_sha":null,"homepage":"https://github.com/paganini2008/easyjpa","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/paganini2008.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-06-14T06:33:42.000Z","updated_at":"2025-06-14T08:45:13.000Z","dependencies_parsed_at":"2025-04-14T10:06:20.443Z","dependency_job_id":"6b786210-b052-4a9a-92e4-72734057679f","html_url":"https://github.com/paganini2008/easyjpa","commit_stats":null,"previous_names":["paganini2008/easyjpa","paganini2008/fastjpa-spring-boot-starter"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/paganini2008/easyjpa","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paganini2008%2Feasyjpa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paganini2008%2Feasyjpa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paganini2008%2Feasyjpa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paganini2008%2Feasyjpa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/paganini2008","download_url":"https://codeload.github.com/paganini2008/easyjpa/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paganini2008%2Feasyjpa/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274728935,"owners_count":25338572,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-11T02:00:13.660Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hibernate-jpa","jpa-persistence-applications","orm-library","spring-boot","springboot-jpa"],"created_at":"2025-03-27T23:20:01.060Z","updated_at":"2025-09-12T00:12:31.909Z","avatar_url":"https://github.com/paganini2008.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\n# EasyJPA – Your Best Partner for JPA Development!\n\n![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.3+-brightgreen?style=for-the-badge\u0026logo=springboot)\n![Hibernate](https://img.shields.io/badge/Hibernate-ORM-yellow?style=for-the-badge\u0026logo=hibernate)\n![JPA](https://img.shields.io/badge/JPA-Jakarta%20Persistence%20API-blue?style=for-the-badge)\n![EasyJPA](https://img.shields.io/badge/EasyJPA-Lightweight-blueviolet?style=for-the-badge)\n\n\n### It's time to say goodbye to JPA Criteria API complexity! EasyJPA makes your code sleek, simple, and powerful!\n\n**EasyJPA** elegantly streamlines JPA's Criteria API with a fully **Lambda-expression-based** and developer-friendly API, making dynamic queries both intuitive and efficient. It significantly reduces SQL/JPQL complexity, accelerates development, and improves code readability, ensuring a clean and concise query experience.\n\nWith comprehensive support for **complex SQL queries**, **EasyJPA** enables seamless execution of **multi-table joins (INNER, LEFT, RIGHT, CROSS JOINs), subqueries, aggregations, computed columns, and filtering operations**. Its **fluent API with full Lambda expression support** allows developers to construct queries programmatically, eliminating the need for raw SQL while retaining maximum flexibility.\n\n## Features\n---------------------------\n* Dynamic Queries\n* Computed and Function-Based Columns\n* Grouping and Filtering\n* Sorting\n* List Queries and Pagination\n* Complex Subqueries\n* Inner Join, Left Join, Right Join, and Cross Join\n* Update and Delete Operations\n* Lambda Expression Support\n* Hibernate Implementation by Default\n\n## Examples\n**1. Query All Users**\n\n```java\n@Autowired\nprivate UserDao userDao;\n\n@BeforeAll\npublic void saveRandomUsers() {\n    List.of(new User(\"Jack\", \"123456\", \"Jack001@jpatest.com\"),\n            new User(\"Petter\", \"123456\", \"Petter002@jpatest.com\"),\n            new User(\"Scott\", \"123456\", \"scott003@jpatest.com\"),\n            new User(\"Lee\", \"123456\", \"lee004@jpatest.com\"),\n            new User(\"Terry\", \"123456\", \"terry005@jpatest.com\")\n           ).forEach(user -\u003e {\n                userDao.save(user);\n           });\n    log.info(\"Total users: {}\", userDao.count());\n}\n\n/**\nHibernate: \n    select\n        u1_0.id,\n        u1_0.email,\n        u1_0.password,\n        u1_0.username \n    from\n        example_user u1_0\n**/\n@Test\npublic void testSelectAll() {\n    userDao.query()\n           .selectThis()\n           .list()\n           .forEach(u -\u003e {\n                log.info(u.toString());\n           });\n}\n```\n\n**2. Basic Search Conditions**\n\n``` java\n/**\nHibernate: \n    select\n        u1_0.id,\n        u1_0.email,\n        u1_0.password,\n        u1_0.username \n    from\n        example_user u1_0 \n    where\n        u1_0.username=? \n        and u1_0.password=?\n**/\n@Test\npublic void testGetUserByUsernameAndPassword() {\n    User user = userDao.query().filter(new FilterList()\n                                          .eq(User::getUsername, \"Jack\")\n                                          .eq(User::getPassword, \"123456\")\n                                       ).selectThis()\n                                       .one();\n    log.info(\"Load user: {}\", user);\n    assertTrue(user != null);\n}\n\n/**\nHibernate: \n    select\n        u1_0.username,\n        u1_0.password \n    from\n        example_user u1_0 \n    where\n        u1_0.email like ? escape '' \n    offset\n        ? rows \n    fetch\n        first ? rows only\n**/\n@ParameterizedTest\n@ValueSource(strings = {\"scott003\", \"lee004\"})\npublic void testGetUserByEmail(String email) {\n    User user = userDao.query()\n                       .filter(new FilterList()\n                                  .like(User::getEmail, email)\n                       ).select(new ColumnList(\n                                   User::getUsername, \n                                   User::getPassword)\n                       ).first();\n    log.info(\"Load user: {}\", user);\n    assertTrue(user != null);\n    \n}\n\n/**\nHibernate: \n    select\n        u1_0.username,\n        u1_0.password,\n        u1_0.email \n    from\n        example_user u1_0 \n    where\n        u1_0.email like ? escape '' \n    offset\n        ? rows \n    fetch\n        first ? rows only\n**/\n@ParameterizedTest\n@ValueSource(strings = {\"abc009\"})\npublic void testGetUserNotFoundByEmail(String email) {\n    User user = userDao.query()\n                       .filter(new FilterList()\n                               .like(User::getEmail, email)\n                       ).select(new ColumnList(\n                                    User::getUsername, \n                                    User::getPassword, \n                                    User::getEmail)\n                       ).first();\n   log.info(\"Load user: {}\", user);\n   assertTrue(user == null);\n}\n\n```\n**3. Nested Query Conditions \u0026 Sorting \u0026 Computed Columns**\n\n``` java\n@Autowired\nprivate ProductDao productDao;\n\n/**\nHibernate: \n    select\n        p1_0.name,\n        p1_0.location,\n        p1_0.price,\n        (p1_0.price*p1_0.discount) \n    from\n        example_product p1_0 \n    where\n        p1_0.price\u003e=? \n        and (\n            p1_0.location=? \n            or p1_0.location=?\n        ) \n    order by\n        4 desc\n **/\n@Test\npublic void test2() {\n    productDao.query(ProductVo.class)\n              .filter(new FilterList()\n                          .gte(Product::getPrice, BigDecimal.valueOf(200))\n                              .and(() -\u003e new FilterList()\n                                         .eq(Product::getLocation, \"Australia\")\n                                             .or()\n                                         .eq(Product::getLocation, \"Thailand\")\n                               )\n              ).sort(JpaSort.desc(Fields.toInteger(4))\n              ).select(new ColumnList(\n                            Product::getName, \n                            Product::getLocation, \n                            Product::getPrice\n                       ).addColumns(\n                            Fields.multiply(Product::getPrice, Product::getDiscount).as(\"actualPrice\"))\n                       ).list().forEach(vo -\u003e {\n                            log.info(vo.toString());\n                       });\n}\n```\n\n**4. Grouping \u0026 Aggregation \u0026 Filtering**\n\n```java\n/**\nHibernate: \n    select\n        p1_0.location,\n        max(p1_0.price),\n        min(p1_0.price),\n        avg(p1_0.price),\n        count(1) \n    from\n        example_product p1_0 \n    group by\n        p1_0.location \n    having\n        avg(p1_0.price)\u003e? \n    order by\n        4 desc \n    offset\n        ? rows\n**/\n@Test\npublic void test4() {\n    productDao.customQuery()\n              .groupBy(new FieldList(Product::getLocation))\n              .having(Restrictions.gt(Fields.avg(Product::getPrice), 50d))\n              .sort(JpaSort.desc(4))\n              .select(new ColumnList(Product::getLocation).addColumns(\n                   Fields.max(Product::getPrice).as(\"maxPrice\"),\n                   Fields.min(Product::getPrice).as(\"minPrice\"),\n                   Fields.avg(Product::getPrice).as(\"avgPrice\"), \n                   Fields.count(1).as(\"amount\"))\n               ).setTransformer(Transformers.asBean(ProductAggregationVo.class))\n               .list().forEach(vo -\u003e {\n                    log.info(vo.toString());\n               });\n}\n```\n**5. Using Function in Columns**\n\n```java\n/**\nHibernate: \n    select\n        ((max(p1_0.price)||?)||min(p1_0.price)),\n        p1_0.location \n    from\n        example_product p1_0 \n    group by\n        p1_0.location \n    offset\n        ? rows\n**/\n@Test\npublic void test5() {\n    productDao.customQuery()\n              .groupBy(\"location\")\n              .select(new ColumnList().addColumns(\n                          Fields.concat(Fields.concat(Fields.max(\"price\", String.class), \"/\"),\n                                        Fields.min(\"price\", String.class)).as(\"repr\")\n                          ).addColumns(Product::getLocation))\n              .setTransformer(Transformers.asBean(ProductAggregationVo.class))\n              .list().forEach(vo -\u003e {\n                  log.info(vo.toString());\n              });\n}\n\n/**\nHibernate: \n    select\n        lower(p1_0.name),\n        upper(p1_0.location) \n    from\n        example_product p1_0 \n    offset\n        ? rows \n    fetch\n        first ? rows only\n**/\n@Test\npublic void test6() {\n    productDao.customQuery()\n              .select(new ColumnList().addColumns(\n                   Function.build(\"LOWER\", String.class, Product::getName).as(\"name\"),\n                   Function.build(\"UPPER\", String.class,Product::getLocation).as(\"location\"))\n              ).list(10).forEach(t -\u003e {\n                   log.info(t.toString());\n              });\n}\n\n/**\nHibernate: \n    select\n        case p1_0.location \n            when ? \n                then cast(? as varchar) \n            when ? \n                then cast(? as varchar) \n            when ? \n                then cast(? as varchar) \n            when ? \n                then cast(? as varchar) \n            when ? \n                then cast(? as varchar) \n            when ? \n                then cast(? as varchar) \n            when ? \n                then cast(? as varchar) \n            when ? \n                then cast(? as varchar) \n            else cast(? as varchar) \n    end,\n    p1_0.location \nfrom\n    example_product p1_0\n**/\n@Test\npublic void test7() {\n     IfExpression\u003cString, String\u003e ifExpression = new IfExpression\u003cString, String\u003e(Product::getLocation)\n                .when(\"Indonesia\", \"Asia\")\n                .when(\"Japan\", \"Asia\")\n                .when(\"China\", \"Asia\")\n                .when(\"Singapore\", \"Asia\")\n                .when(\"Vietnam\", \"Asia\")\n                .when(\"Thailand\", \"Asia\")\n                .when(\"Australia\", \"Oceania\")\n                .when(\"New Zealand\", \"Oceania\")\n                .otherwise(\"Other\");\n     productDao.customQuery().select(new ColumnList()\n                                        .addColumns(ifExpression.as(\"area\"))\n                                        .addColumns(Product::getLocation)\n                                    ).list().forEach(t -\u003e {\n                                         log.info(t.toString());\n                                    });\n}\n```\n**6. Inner Join \u0026 Pagination**\n\n```java\n@Autowired\nprivate OrderDao orderDao;\n\n@Autowired\nprivate OrderProductDao orderProductDao;\n\n/**\nHibernate: \n    select\n        o1_0.id,\n        o1_0.order_date,\n        o1_0.total_price,\n        o1_0.user_id,\n        u1_0.id,\n        u1_0.email,\n        u1_0.password,\n        u1_0.username \n    from\n        example_order o1_0 \n    join\n        example_user u1_0 \n            on u1_0.id=o1_0.user_id \n    where\n        u1_0.username=? \n    order by\n        o1_0.order_date desc\n**/\n@ParameterizedTest\n@ValueSource(strings = {\"Petter\", \"Jack\"})\npublic void test3(String username) {\n    orderDao.customQuery().join(Order::getUser, \"u\", null)\n                          .filter(Restrictions.eq(User::getUsername, username))\n                          .sort(JpaSort.desc(Order::getOrderDate))\n                          .select(new ColumnList()\n                                  .addFields(Fields.root())\n                                  .addTableAlias(\"u\")\n                          ).list().forEach(t -\u003e {\n                              Order order = (Order) t.get(0);\n                              User user = (User) t.get(1);\n                              log.info(\"Order: \" + order + \", User: \" + user);\n                          });\n}\n\n/**\nHibernate: \n    select\n        count(1) \n    from\n        example_order o1_0 \n    join\n        example_user u1_0 \n            on u1_0.id=o1_0.user_id \n    where\n        o1_0.order_date between ? and ? \n    group by\n        o1_0.order_date,\n        u1_0.username \n    having\n        avg(o1_0.total_price)\u003e?\nHibernate: \n    select\n        u1_0.username,\n        o1_0.order_date,\n        avg(o1_0.total_price) \n    from\n        example_order o1_0 \n    join\n        example_user u1_0 \n            on u1_0.id=o1_0.user_id \n    where\n        o1_0.order_date between ? and ? \n    group by\n        o1_0.order_date,\n        u1_0.username \n    having\n        avg(o1_0.total_price)\u003e? \n    order by\n        o1_0.order_date desc \n    offset\n        ? rows \n    fetch\n        first ? rows only\n**/\n@Test\npublic void test4() {\n    orderDao.customPage().join(Order::getUser, \"u\", null)\n                         .filter(Restrictions.between(Order::getOrderDate,\n                                      LocalDate.of(2025, 2, 1).atStartOfDay(),\n                                      LocalDate.of(2025, 2, 28).atStartOfDay())\n                          ).groupBy(new FieldList()\n                                     .addFields(Order::getOrderDate)\n                                     .addFields(User::getUsername)\n                          ).having(Restrictions.gt(Fields.avg(Order::getTotalPrice), 20000D))\n                         .sort(JpaSort.desc(Order::getOrderDate))\n                         .select(new ColumnList()\n                                     .addColumns(User::getUsername)\n                                     .addColumns(Order::getOrderDate)\n                                     .addFields(Fields.avg(Order::getTotalPrice))\n                          ).setTransformer(Transformers.asCaseInsensitiveMap())\n                         .paginate(PageRequest.of(5))\n                         .forEachPage(eachPage -\u003e {\n                             log.info(String.format(\n              \"====================== PageNumber/TotalPage: %s/%s  Total Records: %s =====================\",\n                             eachPage.getPageNumber(), eachPage.getTotalPages(),\n                             eachPage.getTotalRecords()));\n                             eachPage.getContent().forEach(vo -\u003e {\n                                 log.info(vo.toString());\n                             });\n                          });\n}\n\n```\n\n**7. Left Join \u0026 Pagination**\n\n```java\n/**\nHibernate: \n    select\n        count(1) \n    from\n        example_order o1_0 \n    left join\n        example_order_product op1_0 \n            on o1_0.id=op1_0.order_id\nHibernate: \n    select\n        o1_0.id,\n        o1_0.order_date,\n        o1_0.total_price,\n        o1_0.user_id,\n        p1_0.id,\n        p1_0.discount,\n        p1_0.location,\n        p1_0.name,\n        p1_0.price,\n        p1_0.produce_date \n    from\n        example_order o1_0 \n    left join\n        example_order_product op1_0 \n            on o1_0.id=op1_0.order_id \n    left join\n        example_product p1_0 \n            on p1_0.id=op1_0.product_id \n    order by\n        o1_0.order_date desc \n    offset\n        ? rows \n    fetch\n        first ? rows only\n**/\n@Test\npublic void test5() {\n    orderDao.customPage()\n            .leftJoin(Order::getOrderProducts, \"op\", null)\n            .leftJoin(OrderProduct::getProduct, \"p\", null)\n            .sort(JpaSort.desc(Order::getOrderDate))\n            .select(new ColumnList()\n                    .addFields(Fields.root())\n                    .addTableAlias(\"p\")\n            ).setTransformer(Transformers.asMap())\n            .paginate(PageRequest.of(10))\n            .forEachPage(eachPage -\u003e {\n                 log.info(String.format(\n             \"====================== PageNumber/TotalPage: %s/%s  Total Records: %s =====================\",\n                 eachPage.getPageNumber(), eachPage.getTotalPages(),\n                 eachPage.getTotalRecords()));\n                 eachPage.getContent().forEach(vo -\u003e {\n                     log.info(vo.toString());\n                 });\n             });\n}\n\n/**\nHibernate: \n    select\n        count(1) \n    from\n        example_user u1_0 \n    left join\n        example_order o1_0 \n            on u1_0.id=o1_0.user_id \n    join\n        example_order_product op1_0 \n            on o1_0.id=op1_0.order_id \n    join\n        example_product p1_0 \n            on p1_0.id=op1_0.product_id \n    where\n        p1_0.discount is not null \n        and p1_0.id in ((select\n            s1_0.product_id \n        from\n            example_stock s1_0 \n        where\n            s1_0.amount\u003e?)) \n    group by\n        p1_0.name,\n        p1_0.location\nHibernate: \n    select\n        p1_0.name,\n        p1_0.location,\n        count(p1_0.id),\n        count(o1_0.id),\n        sum(op1_0.amount),\n        abs((((p1_0.price*p1_0.discount)*sum(op1_0.amount))-(p1_0.price*sum(op1_0.amount)))) \n    from\n        example_user u1_0 \n    left join\n        example_order o1_0 \n            on u1_0.id=o1_0.user_id \n    join\n        example_order_product op1_0 \n            on o1_0.id=op1_0.order_id \n    join\n        example_product p1_0 \n            on p1_0.id=op1_0.product_id \n    where\n        p1_0.discount is not null \n        and p1_0.id in ((select\n            s1_0.product_id \n        from\n            example_stock s1_0 \n        where\n            s1_0.amount\u003e?)) \n    group by\n        p1_0.name,\n        p1_0.location \n    order by\n        4 desc,\n        5 desc \n    offset\n        ? rows \n    fetch\n        first ? rows only\n**/\n@Test\npublic void test7() {\n    userDao.customPage().leftJoin(User::getOrders, \"o\", null)\n                        .join(Order::getOrderProducts, \"op\", null)\n                        .join(OrderProduct::getProduct, \"p\", null)\n                        .filter(Restrictions.notNull(Product::getDiscount)\n                        .and(Restrictions.in(Product::getId,\n                                productDao.query().subQuery(Stock.class, \"s\", Long.class)\n                                        .filter(Restrictions.gt(Stock::getAmount, 100L))\n                                        .select(Stock::getProductId))))\n                        .groupBy(new FieldList(Product::getName, Product::getLocation))\n                        .sort(JpaSort.desc(4), JpaSort.desc(5))\n                        .select(new ColumnList()\n                                    .addColumns(Product::getName, Product::getLocation)\n                                    .addColumns(Fields.count(Product::getId).as(\"productAmount\"),\n                                                  Fields.count(Order::getId).as(\"orderAmount\"),\n                                         Fields.sum(OrderProduct::getAmount).as(\"totalAmount\"), \n                                         Fields.abs(Fields.minus(\n                                                Fields.multiply(\n                                                        Fields.multiply(Product::getPrice,\n                                                                Product::getDiscount),\n                                                        Fields.sum(OrderProduct::getAmount)),\n                                                Fields.multiply(Product::getPrice,\n                                                        Fields.sum(OrderProduct::getAmount))))\n                                        .as(\"savings\")))\n                        .setTransformer(Transformers.asMap()).paginate(PageRequest.of(10))\n                        .forEachPage(eachPage -\u003e {\n                                     log.info(String.format(\n           \"====================== PageNumber/TotalPage: %s/%s  Total Records: %s ======================\",\n                                     eachPage.getPageNumber(), eachPage.getTotalPages(),\n                                     eachPage.getTotalRecords()));\n                                     eachPage.getContent().forEach(vo -\u003e {\n                                         log.info(vo.toString());\n                                     });\n                         });\n    }\n```\n\n**8. Right Join \u0026 Pagination**\n\n```java\n/**\nHibernate: \n    select\n        count(1) \n    from\n        example_order o1_0 \n    right join\n        example_order_product op1_0 \n            on o1_0.id=op1_0.order_id \n    right join\n        example_product p1_0 \n            on p1_0.id=op1_0.product_id\nHibernate: \n    select\n        o1_0.id,\n        o1_0.total_price,\n        o1_0.order_date,\n        op1_0.amount,\n        p1_0.name,\n        p1_0.location \n    from\n        example_order o1_0 \n    right join\n        example_order_product op1_0 \n            on o1_0.id=op1_0.order_id \n    right join\n        example_product p1_0 \n            on p1_0.id=op1_0.product_id \n    order by\n        o1_0.order_date desc,\n        op1_0.amount desc \n    offset\n        ? rows \n    fetch\n        first ? rows only\n**/\n@Test\npublic void test6() {\n    orderDao.customPage()\n            .rightJoin(Order::getOrderProducts, \"op\", null)\n            .rightJoin(OrderProduct::getProduct, \"p\", null)\n            .sort(JpaSort.desc(Order::getOrderDate), \n                  JpaSort.desc(OrderProduct::getAmount)\n             ).select(new ColumnList()\n                  .addColumns(Order::getId, \n                              Order::getTotalPrice, \n                              Order::getOrderDate)\n                  .addColumns(OrderProduct::getAmount)\n                  .addColumns(Product::getName, \n                              Product::getLocation)\n             ).setTransformer(Transformers.asMap())\n              .paginate(PageRequest.of(10))\n              .forEachPage(eachPage -\u003e {\n                   log.info(String.format(\n            \"====================== PageNumber/TotalPage: %s/%s  Total Records: %s ======================\",\n                   eachPage.getPageNumber(), \n                   eachPage.getTotalPages(),\n                   eachPage.getTotalRecords()));\n                   eachPage.getContent().forEach(vo -\u003e {\n                       log.info(vo.toString());\n                   });\n             });\n}\n```\n\n**9. Cross Join \u0026 Pagination**\n\n``` java\n/**\nHibernate: \n    select\n        count(1) \n    from\n        example_product p1_0,\n        example_stock s1_0 \n    where\n        s1_0.product_id=p1_0.id\nHibernate: \n    select\n        p1_0.id,\n        p1_0.name,\n        s1_0.amount \n    from\n        example_product p1_0,\n        example_stock s1_0 \n    where\n        s1_0.product_id=p1_0.id \n    offset\n        ? rows \n    fetch\n        first ? rows only\n**/\n@Test\npublic void test8() {\n    productDao.customPage()\n              .crossJoin(Stock.class, \"a\")\n              .filter(new FilterList()\n                      .eq(Stock::getProductId, Product::getId)\n              ).select(new ColumnList()\n                       .addColumns(Product::getId, \n                                   Product::getName\n                       ).addColumns(Stock::getAmount)\n              ).setTransformer(Transformers.asBean(ProductStockVo.class))\n               .paginate(PageRequest.of(10))\n               .forEachPage(eachPage -\u003e {\n                    log.info(String.format(\n              \"====================== PageNumber/TotalPage: %s/%s  Total Records: %s =====================\",\n                    eachPage.getPageNumber(), \n                    eachPage.getTotalPages(),\n                    eachPage.getTotalRecords()));\n                    eachPage.getContent().forEach(vo -\u003e {\n                        log.info(vo.toString());\n                    });\n              });\n}\n```\n\n**10. Subquery \u0026  Join**\n\n``` java\n/**\nHibernate: \n    select\n        distinct o1_0.user_id \n    from\n        example_order o1_0 \n    where\n        exists(select\n            1 \n        from\n            example_user u2_0 \n        where\n            u2_0.id=o1_0.user_id)\n**/\n@Test\npublic void test1() {\n    JpaQuery\u003cOrder, Tuple\u003e jpaQuery = orderDao.customQuery();\n    JpaSubQuery\u003cUser, Long\u003e jpaSubQuery = jpaQuery.subQuery(User.class, \"u\", Long.class)\n                                                  .filter(Restrictions.eq(User::getId, Order::getUser))\n                                                  .select(Fields.toLong(1L));\n    jpaQuery.filter(Restrictions.exists(jpaSubQuery))\n            .distinct()\n            .select(new ColumnList(Order::getUser))\n            .list().forEach(m -\u003e {\n                 log.info(m.toString());\n            });\n}\n\n/**\nHibernate: \n    select\n        op1_0.order_id,\n        op1_0.product_id,\n        op1_0.amount,\n        p1_0.name,\n        u1_0.username \n    from\n        example_order_product op1_0 \n    left join\n        example_product p1_0 \n            on p1_0.id=op1_0.product_id \n    join\n        example_order o1_0 \n            on o1_0.id=op1_0.order_id \n    join\n        example_user u1_0 \n            on u1_0.id=o1_0.user_id \n    where\n        exists(select\n            p3_0.id \n        from\n            example_product p3_0 \n        where\n            p3_0.id=op1_0.product_id \n            and p3_0.name=?) \n    offset\n        ? rows \n    fetch\n        first ? rows only\n**/\n@ParameterizedTest\n@ValueSource(strings = {\"Microwave oven\", \"Coffee maker\"})\npublic void test2(String itemName) {\n     JpaQuery\u003cOrderProduct, Tuple\u003e jpaQuery = orderProductDao.customQuery();\n     JpaSubQuery\u003cProduct, Long\u003e jpaSubQuery = jpaQuery.subQuery(Product.class, \"p\", Long.class)\n                                              .filter(new FilterList()\n                                              .eq(Product::getId, OrderProduct::getProduct)\n                                                  .and()\n                                              .eq(Product::getName, itemName)\n                                               ).select(Product::getId);\n     jpaQuery.leftJoin(OrderProduct::getProduct, \"p\", null)\n             .join(Order.class, \"o\", null)\n             .join(User.class, \"u\", null)\n             .filter(Restrictions.exists(jpaSubQuery))\n             .select(new ColumnList(\n                                    OrderProduct::getOrder, \n                                    OrderProduct::getProduct,\n                                    OrderProduct::getAmount\n                                   ).addColumns(Product::getName)\n                                    .addColumns(User::getUsername)\n             ).setTransformer(Transformers.asMap())\n              .list(10)\n              .forEach(m -\u003e {\n                  log.info(m.toString());\n              });\n}\n```\n**11. Update with Subquery**\n```java\n/**\nHibernate: \n    update\n        example_stock s1_0 \n    set\n        amount=(s1_0.amount+cast(? as integer)) \n    where\n        s1_0.product_id in ((select\n            p1_0.id \n        from\n            example_product p1_0 \n        where\n            p1_0.location=?))\n**/\n@ParameterizedTest\n@ValueSource(strings = {\"Australia\", \"New Zealand\"})\npublic void test9(String location) {\n    JpaSubQuery\u003cProduct, Long\u003e subQuery = stockDao.update().subQuery(Product.class, Long.class)\n                .filter(Restrictions.eq(Product::getLocation, location)).select(Product::getId);\n    stockDao.update()\n            .setField(Stock::getAmount, Fields.plusValue(Stock::getAmount, 1000))\n            .filter(Restrictions.in(Stock::getProductId, subQuery))\n            .execute();\n}\n\n/**\nHibernate: \n    select\n        s1_0.product_id \n    from\n        example_stock s1_0 \n    order by\n        s1_0.amount desc \n    offset\n        ? rows \n    fetch\n        first ? rows only\nHibernate: \n    update\n        example_product p1_0 \n    set\n        price=?,\n        discount=?,\n        produce_date=? \n    where\n        p1_0.id=?\n**/\n@Test\npublic void test11() {\n     Long productId = stockDao.query(Long.class)\n                              .sort(JpaSort.desc(Stock::getAmount))\n                              .select(new ColumnList(Stock::getProductId))\n                              .first();\n     int rows = productDao.update().set(Product::getPrice, BigDecimal.valueOf(1000), \n                                        Product::getDiscount,BigDecimal.valueOf(0.8f),                                                               Product::getProduceDate, LocalDate.now())\n                                   .filter(Restrictions.eq(Product::getId, productId))\n                                   .execute();\n     log.info(\"Affected rows: {}\", rows);\n}\n```\n\n**12. Delete with Subquery**\n```java\n/**\nHibernate: \n    delete \n    from\n        example_order o1_0 \n    where\n        exists(select\n            op1_0.order_id \n        from\n            example_order_product op1_0 \n        join\n            example_product p1_0 \n                on p1_0.id=op1_0.product_id \n        where\n            p1_0.id=op1_0.product_id \n            and p1_0.name in (?, ?))\n**/\n@ParameterizedTest\n@CsvSource({\"'Flashlight,Iron'\"})\npublic void test7(String str) {\n     String[] itemNames = str.split(\",\");\n     JpaSubQuery\u003cOrderProduct, Order\u003e subQuery =\n                orderDao.query()\n                        .subQuery(OrderProduct.class, \"o\", Order.class)\n                        .join(OrderProduct::getProduct, \"p\", null)\n                        .filter(new FilterList()\n                                .eq(Product::getId, OrderProduct::getProduct)\n                                .in(Product::getName, List.of(itemNames)))\n                        .select(OrderProduct::getOrder);\n     int rows = orderDao.delete().filter(Restrictions.exists(subQuery)).execute();\n     log.info(\"Affected rows: {}\", rows);\n}\n\n/**\nHibernate: \n    delete \n    from\n        example_user u1_0 \n    where\n        not exists(select\n            o1_0.id \n        from\n            example_order o1_0 \n        where\n            o1_0.user_id=o1_0.id)\n**/\n@Test\npublic void testDeleteUserWithoutOrder() {\n     JpaSubQuery\u003cOrder, Order\u003e subQuery = userDao.delete()\n                                                 .subQuery(Order.class)\n                                                 .filter(Restrictions.eq(Order::getUser, User::getId));\n     int rows = userDao.delete().filter(Restrictions.exists(subQuery).not()).execute();\n     log.info(\"Affected rows: {}\", rows);\n}\n```\n\n## Get Started\n\n* JDK 17 or later\n* Spring Boot 3.x or latest preferred\n* H2, Postgresql, MySQL perfect supported\n* pom.xml\n\n``` xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.github.paganini2008\u003c/groupId\u003e\n    \u003cartifactId\u003eeasyjpa-spring-boot-starter\u003c/artifactId\u003e\n    \u003cversion\u003e1.0.0-RC1\u003c/version\u003e  \u003c!-- use the latest version here --\u003e\n\u003c/dependency\u003e\n```\n\n* Java Configuration\n\n``` java\n@EntityScan(basePackages = {\"com.github.easyjpa.test.entity\"})\n@EnableJpaRepositories(repositoryFactoryBeanClass = EntityDaoFactoryBean.class,\n        basePackages = {\"com.github.easyjpa.test.dao\"})\n@Configuration(proxyBeanMethods = false)\npublic class JpaConfig {\n    \n}\n```\n\n* Entity Definition\n\n```java\n@Entity\n@Table(name = \"example_user\")\npublic class User {\n   ...\n}\n\n@Entity\n@Table(name = \"example_product\")\npublic class Product {\n    ...\n}\n\n@Entity\n@Table(name = \"example_order\")\npublic class Order {\n    ...\n}\n```\n\n* DAO (Repository) Definition\n\n``` java\npublic interface UserDao extends EntityDao\u003cUser, Long\u003e {\n\n}\npublic interface OrderDao extends EntityDao\u003cOrder, Long\u003e {\n\n}\npublic interface ProductDao extends EntityDao\u003cProduct, Long\u003e {\n\n}\n```\n\n## Contribution and License\n\nThis project is open source and licensed under the **MIT License**.\n\n## Project Link\n\nFor more information, visit the **EasyJPA GitHub repository**: [paganini2008/easyjpa](https://github.com/paganini2008/easyjpa).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaganini2008%2Feasyjpa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpaganini2008%2Feasyjpa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaganini2008%2Feasyjpa/lists"}