如何将数据库查询得到的Billing对象转换为Record对象并添加至List<Record>集合?
嘿,这个问题其实是Java强类型特性导致的——Billing和Record是完全不同的类,所以不能直接把Billing对象塞进List<Record>里。我们需要把Billing的属性映射到Record对象中,创建一个符合要求的Record实例再添加进去。下面分几种方式来实现,从最基础的手动映射开始,帮你理解原理:
1. 手动属性映射(最直观,适合理解原理)
这是最基础的方式,你可以清晰看到每一个属性是如何从Billing转移到Record的:
public List<Record> getRecord(List<Request> requests) { List<Record> records = new ArrayList<>(); for (Request request : requests) { Billing billing = billingRepository .findByBillingCycleAndStartDateAndEndDate( request.getBillingCycle() , request.getStartDate() , request.getEndDate()); if (billing != null) { // 1. 创建一个空的Record对象 Record record = new Record(); // 2. 映射两个类共有的属性 record.setBillingCycle(billing.getBillingCycle()); record.setStartDate(billing.getStartDate()); record.setEndDate(billing.getEndDate()); record.setAmount(billing.getAmount()); // 3. 映射关联的Account属性(注意空指针判断!) Account account = billing.getAccountId(); if (account != null) { record.setAccountName(account.getAccountName()); // 假设Account类有对应getter record.setFirstName(account.getFirstName()); // 假设Account类有对应getter record.setLastname(account.getLastname()); // 假设Account类有对应getter } // 4. 将转换后的Record添加到列表 records.add(record); } } return records; }
原理说明:
Java是强类型语言,集合List<Record>只能存储Record类型的对象。我们通过手动读取Billing对象的属性值,调用Record的setter方法把值赋值进去,生成一个全新的Record实例,这样就符合集合的类型要求了。
另外要注意billing.getAccountId()可能为null,所以一定要加空判断,避免NullPointerException。
2. 封装转换逻辑(代码更整洁,复用性强)
如果这个转换逻辑在多个地方用到,我们可以把转换逻辑封装到Record类里,比如添加一个静态工厂方法或者构造器:
方式2.1:添加静态工厂方法到Record类
public class Record { // 原有的属性、构造器、getter/setter保持不变 // 新增静态方法,接收Billing对象返回Record实例 public static Record fromBilling(Billing billing) { if (billing == null) { return null; } Record record = new Record(); record.setBillingCycle(billing.getBillingCycle()); record.setStartDate(billing.getStartDate()); record.setEndDate(billing.getEndDate()); record.setAmount(billing.getAmount()); Account account = billing.getAccountId(); if (account != null) { record.setAccountName(account.getAccountName()); record.setFirstName(account.getFirstName()); record.setLastname(account.getLastname()); } return record; } }
然后在你的业务方法里就可以简化成:
if (billing != null) { records.add(Record.fromBilling(billing)); }
方式2.2:添加接收Billing的构造器
public class Record { // 原有的属性、无参构造器、getter/setter保持不变 // 新增接收Billing的构造器 public Record(Billing billing) { if (billing == null) { return; } this.billingCycle = billing.getBillingCycle(); this.startDate = billing.getStartDate(); this.endDate = billing.getEndDate(); this.amount = billing.getAmount(); Account account = billing.getAccountId(); if (account != null) { this.accountName = account.getAccountName(); this.firstName = account.getFirstName(); this.lastname = account.getLastname(); } } }
业务方法里的调用就变成:
if (billing != null) { records.add(new Record(billing)); }
原理说明:
把转换逻辑封装到目标类(Record)中,符合单一职责原则,同时让业务代码更简洁,也方便后续修改转换规则时只需要改一处地方。
3. 进阶:使用对象映射工具(减少重复代码)
如果你的项目中有很多类似的对象转换需求,可以使用像ModelMapper这样的工具库,它能自动匹配同名属性进行映射,减少手动写setter的工作量。
步骤:
- 先在项目中引入ModelMapper依赖(比如Maven):
<dependency> <groupId>org.modelmapper</groupId> <artifactId>modelmapper</artifactId> <version>3.1.1</version> </dependency>
- 配置ModelMapper(可以定义为Spring Bean,或者直接创建实例):
ModelMapper modelMapper = new ModelMapper(); // 对于不同名的属性或者关联对象,可以配置映射规则 modelMapper.typeMap(Billing.class, Record.class) .addMapping(Billing::getAccountId, (dest, value) -> { Account account = (Account) value; if (account != null) { dest.setAccountName(account.getAccountName()); dest.setFirstName(account.getFirstName()); dest.setLastname(account.getLastname()); } });
- 业务方法中使用:
if (billing != null) { Record record = modelMapper.map(billing, Record.class); records.add(record); }
原理说明:
对象映射工具通过反射机制读取源对象的属性,自动匹配目标对象的同名属性进行赋值,对于特殊的映射规则(比如关联对象、不同名属性)可以通过配置来定义,大大减少了手动编写转换代码的工作量,适合大型项目使用。
内容的提问来源于stack exchange,提问作者Grid

