利用反射快速给Model实体赋值

public class BaseModel<T> where T : new()  
{  
    public static T Init(DataRow dr)  
    {  
        T t = new T();  
        Type infotype = typeof(T);  
        //获取所有属性  
        PropertyInfo[] propertys = infotype.GetProperties();  
        //遍历属性并将datarow中字段的值赋值给同名属性  
        foreach (PropertyInfo pi in propertys)  
        {  
          infotype.GetProperty(pi.Name).SetValue(t, result, null);  
        }  
        return t;  
    }  
}  
  
BaseModel<Student>.Init(dr)  


试想这样一个业务需求:有一张合同表,由于合同涉及内容比较多所以此表比较庞大,大概有120多个字段。现在合同每一次变更时都需要对合同原始信息进行归档一次,版本号依次递增。那么我们就要新建一张合同历史表,字段跟原合同表一模一样,此外多了一个 合同版本号 字段。在归档时如何把原始合同信息插入到合同历史表呢?

        很容易就能想到的一种解决方法:

insert into 合同历史表(字段1,字段2,字段3…………字段120,版本号) select   字段1,字段2,字段3…………字段120,0 as 版本号 from 合同表 where 合同ID=‘xxxxxxx’

这样当然是能实现我们的功能的,但是看到了吗?由于表的字段太多,导致SQL看起来很不优雅,而且字段之间的对应很容易出问题。联想起之前看过的 利用反射给model赋值的例子想出来下面的一个解决方法:

       现在假设两个实体class1、class2,class2只比class1多一个字段newid,其它字段一模一样。简单定义如下:



class Class1  
    {  
        private string id;  
  
        public string Id  
        {  
            get { return id; }  
            set { id = value; }  
        }  
        private string name;  
  
        public string Name  
        {  
            get { return name; }  
            set { name = value; }  
        }  
        private int age;  
  
        public int Age  
        {  
            get { return age; }  
            set { age = value; }  
        }  
        private int num;  
  
        public int Num  
        {  
            get { return num; }  
            set { num = value; }  
        }  
  
    }  


class Class2  
    {  
        private string newid;  
  
        public string Newid  
        {  
            get { return newid; }  
            set { newid = value; }  
        }  
  
        private string id;  
  
        public string Id  
        {  
            get { return id; }  
            set { id = value; }  
        }  
        private string name;  
  
        public string Name  
        {  
            get { return name; }  
            set { name = value; }  
        }  
        private int age;  
  
        public int Age  
        {  
            get { return age; }  
            set { age = value; }  
        }  
        private int num;  
  
        public int Num  
        {  
            get { return num; }  
            set { num = value; }  
        }  
    }  

下面我们给class1赋值,然后通过反射获取class2的属性,循环把class1对应的值赋给class2,遇到class2多出的字段我们手功处理后跳过。简单代码如下:

Class1 c1 = new Class1();  
         c1.Id = "001";  
         c1.Name = "ben.jiang";  
         c1.Num = 712104195;  
         c1.Age = 24;  
  
         Class2 c2 = new Class2();  
         Type t2 = typeof(Class2);  
         PropertyInfo[] propertys2 = t2.GetProperties();  
  
         Type t1 = typeof(Class1);  
         PropertyInfo[] propertys1 = t1.GetProperties();  
  
         foreach (PropertyInfo pi in propertys2)  
         {  
             string name = pi.Name;  
             if (name == "Newid")  
             {  
                 c2.Newid = "newid";  
                 continue;  
             }  
  
             object value=t1.GetProperty(name).GetValue(c1, null);  
             t2.GetProperty(name).SetValue(c2,value ,null);  
         }  

这样代码看起来稍微优雅了一些,而且针对不同的字段我们处理起来也方便。


在Java中,当需要将两个实体类中不同名称的字段进行赋值时,可以通过多种方式实现。以下是一些常见的解决方案: ### 使用 MapStruct 实现字段映射 MapStruct 是一个代码生成器,它基于注解处理器在编译期生成映射代码,可以有效地减少运行时的性能开销[^3]。下面是一个简单的例子来展示如何使用 MapStruct 来映射不同名称的字段。 首先定义两个实体类 `xxbmVO` 和 `SchoolVO`,它们具有不同的字段名: ```java public class xxbmVO { private String xxbm; private String xxmc; // getters and setters } public class SchoolVO { private String code; private String name; // getters and setters } ``` 然后创建一个映射接口 `SchoolMapper`: ```java import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; @Mapper public interface SchoolMapper { SchoolMapper INSTANCT = Mappers.getMapper(SchoolMapper.class); @Mapping(source = "xxbm", target = "code") @Mapping(source = "xxmc", target = "name") SchoolVO cover(xxbmVO vo); } ``` 最后,在主程序中使用这个映射器来进行转换: ```java public static void main(String[] args) { xxbmVO vo = new xxbmVO(); vo.setXxbm("学校编码"); vo.setXxmc("学校名称"); SchoolVO conver = SchoolMapper.INSTANCT.cover(vo); String schoolCode = conver.getCode(); String schoolName = conver.getName(); System.out.println(schoolCode); System.out.println(schoolName); } ``` ### 使用 Java 反射机制手动映射 如果不想使用第三方库,也可以通过 Java 的反射机制手动实现字段映射。这种方法较为繁琐,但提供了更大的灵活性。例如,可以编写一个通用的方法来处理这种情况: ```java public static void mapFields(Object source, Object target) throws Exception { Class<?> sourceClass = source.getClass(); Class<?> targetClass = target.getClass(); Field[] sourceFields = sourceClass.getDeclaredFields(); Field[] targetFields = targetClass.getDeclaredFields(); for (Field sourceField : sourceFields) { sourceField.setAccessible(true); Object value = sourceField.get(source); for (Field targetField : targetFields) { if (sourceField.getName().equals(targetField.getName())) { targetField.setAccessible(true); targetField.set(target, value); } } } } ``` 需要注意的是,上述方法仅适用于字段名称相同的情况。对于字段名称不同的情况,则需要额外的逻辑来匹配源字段与目标字段。 ### 使用 Apache Commons BeanUtils 或其他工具库 Apache Commons BeanUtils 提供了简单的方法来复制属性,但是它不支持类型转换,并且对于复杂的映射需求可能不够灵活。此外,还有其他的开源库如 Dozer、ModelMapper 等也提供了更高级的功能。 综上所述,推荐使用 MapStruct 这样的现代框架来处理不同名称字段之间的映射问题,因为它不仅能够提高开发效率,还能保证良好的性能表现。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值