使用反射机制实现实体列表到DataTable的深层字段转换

在《适配器模式在Web Service返回值中的应用》(http://blog.csdn.net/zhmnsw/archive/2007/07/23/1704235.aspx)一文中,我们使用到了IDataListAdapter接口来实现返回值数据表的转换操作,其中对于NHibernate返回的实体列表我们使用了TDlaEntityList类来进行转换。

但是,对于TDlaEntityList类型的实现,参考的一些代码只考虑到了基本数据类型字段的转换,而对于非系统定义的数据类型,或者具有组合性质的字段属性,该转换属于无效转换。比如一个Person和一个Address类型,为多对一关系,那么当Person包含一个Address类型的组合字段时,我们便无法将该字段简单的放入DataTable表中,而必须确定一个Address字段的别名字段。因此,本文描述了一种使用反射机制,填充实体列表组合字段值的方法。
一般情况下,对于基本数据类型字段,我们只需要使用PropertyInfo的GetValue方法及PropertyType属性等操作,就可以方便的将对象具有的各字段值一一读出,对于这类代码,网上有很多实现代码,在此不再赘述。
而对于我们上面提到的组合字段,由于无法预知字段嵌套的深度,比如对于多个类型连接的情况,我们可能会使用类似person.Address.Area.Areaname的语句形式来读取我们需要的映射字段值。那么,我们可不可以在使用TDlaEntityList类型进行“实体-数据记录”数据转换的时候,根据所设定的搜寻路径来自动寻找我们要转换的字段值呢?答案是肯定的,我们一步一步来。
对于TDlaEntityList类型我们应该先定义字段在DataTable中的别名、数据类型以及改别名值的搜寻路径,比如,我们设置一个组合字段的别名为BelongUserName、System.String类型,以及搜寻路径为BlongUser.UserName,那么在实体列表转换成DataTable型的时候会遵循以下算法:
1、 使用反射机制读取一个字段,并判断该字段是否为组合数据类型。
2、 如果不是,则返回该字段值,回到1。如果是,则继续。
3、 读取该组合字段的第一层字段名称(比如对于BlongUser.UserName,则返回BlongUser),并读取该层字段的值,并判断该值是否有下一级的组合字段。
4、 如果存在下一级组合字段,则去掉上层名称,回到步骤3,递归获取字段值。
5、 如果不存在下一级组合字段,且当前字段为基本数据类型,则返回该值。
6、 如果当前字段不是基本数据类型,则返回空(或者返回一个特定的快捷方式,此实现另文叙述)
注意:
      对于为空的组合字段值,直接返回空值(递归到哪层都会如此)
      如指定的搜寻路径无法找到,则返回空值
     对于指定的数据类型与实际字段数据类型的冲突,需要你自己负责
那么根据该算法,我们便可是根据指定的别名及搜寻路径,填充DataTable字段值。具体实现代码如下(.NET C#)
using System;
using System.Data;
using System.Collections;
using System.Reflection;
using QihangSoft.StringData;

namespace QihangSoft.Communication {


    
public class TDlaEntityList: QihangSoft.Communication.IDataListAdapter {
        
IDataList 成员


        
public TDlaEntityList( IList entityList) {
            
//初始化各列表
            FEntityList = entityList;
            FRecursionPropertyList 
= new TStrList();
            FRecursionPropertyTypeList 
= new ArrayList();
        }


        
private IList FEntityList;
        
private TStrList FRecursionPropertyList; //组合属性字段名称及搜寻路径列表
        private ArrayList FRecursionPropertyTypeList; //组合字段属性类型列表

        
/// <summary>
        
/// 实体列表转换成DataTable
        
/// </summary>
        
/// <returns></returns>

        private DataTable ilistToTable()
        
{
            DataTable dt 
= new DataTable();
            TStrList noSysType 
= new TStrList();
            
if ((FEntityList != null)&&(FEntityList.Count >0))
            
{
                
//获取反射属性信息
                System.Reflection.PropertyInfo[] columnList = getObjectPropertyInfo(FEntityList[0]);

                
//遍历属性列表,存入DataTable
                foreach(System.Reflection.PropertyInfo column in columnList)
                
{

                    
//获取非系统类型字段列表,以便返回实体快捷方式
                    System.Type typeimp = System.Type.GetType(column.PropertyType.ToString());
                    
if (typeimp == null)
                    
{
                        noSysType.addNew(column.Name, column.Name);

                        
//dt.Columns.Add(column.Name, System.Type.GetType(“System.String”));            
                    }

                    
else
                    
{
                        dt.Columns.Add(column.Name, typeimp);
                    }

                }


                
//载入递归字段类型
                for    (int a=0; a<FRecursionPropertyList.count; a++)
                
{
                    dt.Columns.Add(FRecursionPropertyList.getName(a), (System.Type)(FRecursionPropertyTypeList[a]));
                }


                
//遍历整个IList,获取数据
                for(int i=0; i<FEntityList.Count; i++)
                
{
                    IList TempList 
= new ArrayList();
                    
//将IList中一条记录的有效属性字段写入ArrayList
                    foreach (System.Reflection.PropertyInfo pi in columnList)
                    
{
                        
//未在排除列表中出现的字段为有效属性字段
                        if (noSysType.valueByName(pi.Name) == TStrDefine.NULL_STR)
                        
{
                            
object oo = pi.GetValue(FEntityList[i], null);
                            TempList.Add(oo);
                        }

                    }


                    
object[] itm=new object[TempList.Count + FRecursionPropertyList.count];
                    
//遍历ArrayList向object[]里放数据

                    
for (int j = 0; j < TempList.Count; j++)
                    
{
                        itm.SetValue(TempList[j], j);
                    }

                    
//遍历递归数据
                    for(int k =0; k<FRecursionPropertyList.count; k++)
                    
{
                        
object obj = getPropertyValue(FEntityList[i], FRecursionPropertyList.getValue(k));
                        itm.SetValue(obj, TempList.Count
+k);
                    }


                    
//将object[]的内容放入DataTable
                    dt.LoadDataRow(itm, true);
                }

            }

            
return dt;

        }


        
/// <summary>
        
/// 设置递归属性字段
        
/// </summary>
        
/// <param name=”columnName”>属性别名</param>
        
/// <param name=”recursionName”>递归属性名称</param>
        
/// <param name=”recursionType”>属性数据类型</param>

        public void setRecursionField(string columnName, string recursionName, System.Type recursionType)
        
{
            FRecursionPropertyList.addNew(columnName, recursionName);
            FRecursionPropertyTypeList.Add(recursionType);
        }


        
/// <summary>
        
/// 获取实体类型的属性列表
        
/// </summary>
        
/// <param name=”obj”>传入的实体</param>
        
/// <returns></returns>

        private System.Reflection.PropertyInfo[] getObjectPropertyInfo(object obj)
        
{
            
if (obj != null)
            
{
                
return obj.GetType().GetProperties();
            }

            
else
            
{
                
return null;
            }

        }


        
/// <summary>
        
/// 递归函数,获取属性值
        
/// </summary>
        
/// <param name=”obj”>传入的实体对象</param>
        
/// <param name=”propertyName”>属性名称</param>
        
/// <returns></returns>

        private object getPropertyValue(object obj, string propertyName)
        
{
            
//取得propertyName第一段属性字符串
            string topPropertyName = getTopPropertyName(propertyName);

            
if (obj != null)
            
{
                System.Reflection.PropertyInfo pi 
= obj.GetType().GetProperty(topPropertyName);

                
string subPropertyName = deleteTopPropertyName(propertyName);

                
if (!“”.Equals(subPropertyName))
                
{
                    
//如果还有下一级属性名称,则递归获取字段值

                    
return getPropertyValue(pi.GetValue(obj, null), subPropertyName);

                }

                
else
                
{
                    
//如果没有下一级属性名称,则返回指定字段值
                    return pi.GetValue(obj, null);
                }

            }

            
else
            
{
                
return null;
            }

        }


        
/// <summary>
        
/// 获取属性名称顶部名称值,例如:BlongUser.UserName,则返回BlongUser
        
/// </summary>
        
/// <param name=”propertyName”>传入的属性名称</param>
        
/// <returns></returns>

        private string getTopPropertyName(string propertyName)
        
{
            
//搜索点号“.”的位置
            if (! “”.Equals(propertyName))
            
{
                
string[] strList = propertyName.Split(.);
                
if (strList.Length >0)
                
{
                    
return strList[0];
                }

                
else
                
{
                    
return “”;
                }

            }

            
else
            
{
                
return “”;
            }

        }


        
/// <summary>
        
/// 删除属性名称顶部名称值,例如:BlongUser.UserName,则返回UserName
        
/// </summary>
        
/// <param name=”propertyName”>传入的属性名称</param>
        
/// <returns></returns>

        private string deleteTopPropertyName(string propertyName)
        
{
            
if (! “”.Equals(propertyName))
            
{
                
int dotPos = propertyName.IndexOf(.);
                
if (dotPos >-1)
                
{

                    
return propertyName.Remove(0, dotPos+1);
                }

                
else
                
{
                    
return “”;
                }

            }

            
else
            
{
                
return “”;
            }

        }

    }

}


标签: ,
文章分类 FK Coding

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

点赞
如果您觉得很赞,我将非常乐意接受虚拟币的捐赠,以示您对我的肯定。

比特币钱包地址:
1PqpqA8FyH3NbfCrbcRd1YxQk3LEsSEYDV
莱特币钱包地址:
LRTdmovGGVEHCKWz7JdL9aiB7VZkuNycJf
站点勋章
网站统计