通过反射机制,对将要入库的实体对象的各个属性进行判断,得到最终要更新的实体对象

本文探讨如何通过反射机制,对实体对象的属性进行非空判断和一致性比较,以确定更新数据库记录所需的具体属性值。包括判断属性值是否为空、与旧值是否相同以及在属性值变化时如何正确更新数据库。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如题,本将要实现的功能:通过反射机制,对将要入库的实体对象的各个属性进行判断,得到最终要更新的实体对象。

应用场景:当我们需要修改数据库中某条记录时,常常需要判断新的对象(客户端修改好提交到后台的实体对象)中哪些属性是没有值的,

以免这个新的实体把原来数据库中的某些字段用null或""把数据库中的相应字段“置空”。

下面我们通过判断:

1.新的实体对象的属性值是否为空,如果某个属性值为空,保留旧的实体对象的这个属性值。

2.数据库中某条记录所对应的实体(如通过hibernate将数据库记录装入的实体对象)和新的实体对象中的属性值是否相同,如果相同保留旧的实体对象的这个属性值。

3.如果新的实体对象的属性值不为空而且与旧的实体对象相对应的属性值不同,那么就使用这个新的实体中的属性值来作为入库对象的属性值。

根据以上三点来得到新的要入库的实体对象。在下面的代码中你会发现,为了得到实体中属性值,这里使用的是属性相应的get方法而不是直接访问属性值,虽然通过Field也能得到属性值,但我认为应该充分尊重实体类的创建者对属性和方法设置的作用域,应该只访问那些实体创建者给我们暴露的方法而不是通过setAccessible来暴力访问那些隐私的属性或方法。

  /**
	 * 对实体对象的属性值进行非空判断和一致性比较之后得到要更新的实体对象。
	 * 
	 * @param beanClass  		实体类类型
	 * @param newBean    		新的实体对象
	 * @param oldBean	 	 	数据库中的记录对应的实体对象
	 * @param ignoreAttrNames	需要忽略比较新旧的属性名,它将仍然保持旧的属性值(通常是对应主键的属性)
	 * @return           		需要入库的实体对象
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 */
	public static <T> T compareBeanAttr(Class<T> beanClass, T newBean, T oldBean, String... ignoreAttrNames)
			throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
		
		//得到实体类的所有方法
		Method[] beanMethods = beanClass.getDeclaredMethods();
		
		//得到所有名称为: “getXxx”方法和“setXxx”方法,“Xxx”为属性名首字大写后的名称。
		final String preGet = "get";
		final String preSet = "set";
		final List<Method> getMethods = new ArrayList<Method>();
		final List<Method> setMethods = new ArrayList<Method>();
		for(Method method:beanMethods){
			String methodName = method.getName();
			//得到get方法
			if(preGet.equals(methodName.substring(0, preGet.length()))){
				getMethods.add(method);
			}
			//得到set方法
			else if(preSet.equals(methodName.substring(0, preSet.length()))){
				setMethods.add(method);
			}
		}
		
		/*
		 * 判断newBean:
		 * 1.newBean对应的get方法的得到的属性值是否为空(null或"")
		 * 2.比较newBean和oldBean对应get方法得到的属性值是否相同
		 */
		
		 //判读是否需要重置数据库中列值的标记
		boolean isNeedReset = false;   
		for(Method getMethod:getMethods){
			Object newValue = getMethod.invoke(newBean);
			Object oldValue = getMethod.invoke(oldBean);
			//得到get方法名
			String getMethodName = getMethod.getName(); 
			//得到首字母为大写的属性名
			String lastName = getMethodName.substring(preSet.length()); 
			//把首字转成小写后称为属性名
			String attrName = lastName.substring(0, 1).toLowerCase() + lastName.substring(1); 
			//判断方法对应的属性是否为需要忽略的属性
			boolean isNeedIgnore = false;
			for(String ignoreAttrName:ignoreAttrNames){
				if(ignoreAttrName.equals(attrName)){
					//忽略那些不需要更新的属性值
					isNeedIgnore = true;
					break;
				}
			}
			if(isNeedIgnore){
				//忽略这个属性的get方法,继续下一个
				continue;
			}
			//得到对应的set方名
			String setMethodName = preSet + lastName; 
			//判断新实体的属性值中是否有值,以及新实体和旧实体对应的属性值是否相同
			if(newValue != null && !newValue.equals(oldValue)){
				
				if(newValue instanceof String){ 
					//如果是字符串类型的还要判断是否为""
					if(!"".equals(( (String)newValue).trim() )){
						//需要重置数据库中的值
						isNeedReset = true; 
					}
					else{
						isNeedReset = false;
					}
				}else{ //其他类型的属性,可以直接存入数据库中
					
					//需要重置数据库中的值
					isNeedReset = true; 
				}
				
				//判断是否要重置数据库中的值
				if(isNeedReset){
					//调用对应的set方法,重置数据库中的值
					for(Method setMethod:setMethods){
						if(setMethodName.equals(setMethod.getName())){
							//调用相应的set方法
							setMethod.invoke(oldBean, newValue);  
						}
					}
					//重置标记,为下次判断准备
					isNeedReset = false;
				}
			}
		}
		
		return oldBean;
	}
	


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值