0

0

如何在 Spring Data JPA 中使用 DTO 投影获取数据

碧海醫心

碧海醫心

发布时间:2024-12-01 09:33:23

|

960人浏览过

|

来源于dev.to

转载

如何在 spring data jpa 中使用 dto 投影获取数据

介绍

在这篇文章中,我们将探讨投影在 spring data jpa 中的工作原理,讨论不同的类型,并通过示例来演示它们如何简化数据访问

对于本指南,我们使用:

  • ide:intellij idea(推荐用于 spring 应用程序)或 eclipse
  • java 版本:17
  • spring data jpa 版本:2.7.x 或更高版本(兼容 spring boot 3.x)
  • 使用的实体:用户(代表用户个人资料)和地址(代表用户的地址详细信息)

注意:有关更详细的示例,请访问我的 github 存储库

@setter
@getter
@entity(name = "tbl_address")
public class address {
    @id
    @generatedvalue(strategy = generationtype.identity)
    private long id;

    private string street;
    private string city;
    private string state;
    private string country;
    private string zipcode;
}
@setter
@getter
@entity(name = "tbl_user")
public class user {
    @id
    @generatedvalue(strategy = generationtype.identity)
    private long id;

    private string firstname;
    private string lastname;
    private string email;
    private string status;

    @onetoone(cascade = cascadetype.all)
    @joincolumn(name = "address_id", referencedcolumnname = "id")
    private address address;
}

1. 为什么在 spring data jpa 中使用投影?

通常,您的应用程序仅需要实体字段的子集,加载不必要的数据可能会导致:

  • 内存使用量增加
  • 查询速度慢
  • 处理连接数据时的复杂实体管理

投影使您能够仅以所需的确切格式获取所需的数据,从而帮助我们避免出现问题。当为 restful api 获取数据时,这特别有用,其中响应不需要实体的所有字段。

2. spring data jpa 中的投影类型。

spring data jpa 提供多种类型的投影:

  • 基于界面的投影
  • 基于类的投影(dto 投影)

2.1 - 基于界面的投影

基于接口的投影允许我们为要检索的字段定义带有 getter 方法的接口。然后,spring data jpa 将使用这些 getter 将实体的字段映射到接口。

  • 示例:

定义投影接口和存储库类:

@repository
public interface userrepository extends jparepository {
    @query("""
        select
            concat(u.firstname, ' ', u.lastname) as fullname,
            u.email as email,
            concat( a.street, ', ', a.city, ', ', a.state) as fulladdress,
            a.country as country,
            a.zipcode as zipcode
        from tbl_user u
        left join tbl_address a on  u.address.id = a.id
    """)
    list findalluserinfo();

    interface userinfoprojection {
        string getfullname();
        string getemail();
        string getfulladdress();
        string getcountry();
        string getzipcode();
    }
}

定义一个 dto 类以从投影传输到 dto。

@builder
@setter
@getter
public class userdto {
    private string fullname;
    private string email;
    private string address;
    private string country;
    private string zipcode;

    public static userdto of(userrepository.userinfoprojection entity) {
        if (objects.isnull(entity))
            return null;

        return userdto.builder()
                .fullname(entity.getfullname())
                .email(entity.getemail())
                .address(entity.getfulladdress())
                .country(entity.getcountry())
                .zipcode(entity.getzipcode())
                .build();
    }
}
  • 测试:
@springboottest
@autoconfiguremockmvc
class querytypesapplicationtests {
    @autowired
    private userrepository userrepository;

    @test
    public void testderivedquerymethods() {
        list results =  userrepository.findalluserinfo()
                .stream()
                .map(userdto::of)
                .tolist();

        assertequals(10, results.size(), "expected 10 users");
    }

}

2.2 - 基于类的预测

通过基于类的投影,我们可以使用自定义 dto 直接映射结果。这种方法可以让您更好地控制数据的结构,如果您需要在构造函数中自定义逻辑,这种方法会很有用。

  • 示例:

定义 dto:

Cutout.Pro抠图
Cutout.Pro抠图

AI批量抠图去背景

下载
@setter
@getter
public class userprojectiondto {
    private final string fullname;
    private final string email;
    private final string address;
    private final string country;
    private final string zipcode;

    public userprojectiondto(string fullname, string email, string address, string country, string zipcode) {
        this.fullname = fullname;
        this.email = email;
        this.address = address;
        this.country = country;
        this.zipcode = zipcode;
    }
}

定义存储库类并编写sql查询来获取用户信息。

@repository
public interface userrepository extends jparepository {

    @query(
        """
            select new com.davidnguyen.querytypes.user.userprojectiondto(
                concat(u.firstname, ' ', u.lastname),
                u.email,
                concat(a.street, ', ', a.city, ', ', a.state),
                a.country,
                a.zipcode
            )
            from tbl_user u left join tbl_address a on u.address.id = a.id
        """
    )
    list findalluserinfo();
}

spring data jpa 执行一个查询,为每行数据构造一个 dto,仅选择构造函数中指定的字段。

  • 测试:
@SpringBootTest
@AutoConfigureMockMvc
class QueryTypesApplicationTests {
    @Autowired
    private UserRepository userRepository;

    @Test
    public void testDerivedQueryMethods() {
        List users = userRepository.findAllUserInfo();

        assertEquals(10, users.size(), "Expected 10 users");
    }

}

3. 选择正确的投影类型

每种投影类型都有其用例:

  • 基于界面的投影非常适合简单的字段选择。
  • 基于类的投影更适合复杂的转换或自定义逻辑。

性能说明:

  • 复杂的投影可能会导致过于复杂的查询,这可能会影响性能。
  • 使用 dto 的基于类的投影会带来开销,特别是对于大型结果集,因为每一行都需要一个新的 dto 实例。因此,请始终根据需要监控和优化查询。

4. spring data jpa 中 dto 投影的最佳实践。

  • 仅选择您需要的字段:无论使用基于类还是基于接口的投影,始终将选择限制为仅必要的字段以优化数据库负载。

  • 对 dto 使用不变性:对于基于类的投影,创建不可变的 dto(最终字段,无 setter)以使其安全稳定。

  • 考虑复杂联接的本机查询:如果您的投影涉及复杂联接或计算字段,请考虑使用带有 @sqlresultsetmapping 和 @constructorresult 注释的本机 sql 查询以获得更多控制。

  • 分析性能查询:特别是对于大型数据集,使用分析工具(如 jpa/hibernate 日志记录)来监视查询性能并确保您的投影不会无意中加载额外的数据。

总结

spring data jpa 中的投影提供了强大的选项来控制从查询返回的数据。通过使用基于接口、基于类和动态投影,您可以微调数据检索以满足应用程序的要求。请记住,有效地实施投影可以提高数据处理的效率,尤其是在具有大型数据集的应用程序中。

下一篇文章见。快乐编码!

访问我的博客以获取更多帖子。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

751

2023.10.12

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

328

2023.10.27

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

350

2024.02.23

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

1304

2024.03.06

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

361

2024.03.06

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

881

2024.04.07

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

581

2024.04.29

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

425

2024.04.29

2026赚钱平台入口大全
2026赚钱平台入口大全

2026年最新赚钱平台入口汇总,涵盖任务众包、内容创作、电商运营、技能变现等多类正规渠道,助你轻松开启副业增收之路。阅读专题下面的文章了解更多详细内容。

54

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Git 教程
Git 教程

共21课时 | 3.2万人学习

Git版本控制工具
Git版本控制工具

共8课时 | 1.5万人学习

Git中文开发手册
Git中文开发手册

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号