把object转换成DataSet,进行数据绑定

概述:

    当我们遇到把对象的属性及值显示在GridView的时候,我们需要把ojbect转化为DataTable来进行绑定.

代码如下:  

///   <summary>
    
///  Fills the DataSet with data from an object or collection.
    
///   </summary>
    
///   <remarks>
    
///  The name of the DataTable being filled is will be the class name of
    
///  the object acting as the data source. The
    
///  DataTable will be inserted if it doesn't already exist in the DataSet.
    
///   </remarks>
    
///   <param name="ds"> A reference to the DataSet to be filled. </param>
    
///   <param name="source"> A reference to the object or collection acting as a data source. </param>
     public   void  Fill(DataSet ds,  object  source)
    {
        
string  className  =  source.GetType().Name;
        Fill(ds, className, source);
    }

 

///   <summary>
    
///  Fills the DataSet with data from an object or collection.
    
///   </summary>
    
///   <remarks>
    
///  The name of the DataTable being filled is specified as a parameter. The
    
///  DataTable will be inserted if it doesn't already exist in the DataSet.
    
///   </remarks>
    
///   <param name="ds"> A reference to the DataSet to be filled. </param>
    
///   <param name="TableName"></param>
    
///   <param name="source"> A reference to the object or collection acting as a data source. </param>
     public   void  Fill(DataSet ds,  string  tableName,  object  source)
    {
        DataTable dt;
        
bool  exists;

        dt 
=  ds.Tables[tableName];
        exists 
=  (dt  !=   null );

        
if  ( ! exists)
            dt 
=   new  DataTable(tableName);

        Fill(dt, source);

        
if  ( ! exists)
            ds.Tables.Add(dt);
}

通过重载,使ojbect转化DataSet过渡到转化DataTable.

///   <summary>
    
///  Fills a DataTable with data values from an object or collection.
    
///   </summary>
    
///   <param name="dt"> A reference to the DataTable to be filled. </param>
    
///   <param name="source"> A reference to the object or collection acting as a data source. </param>
     public   void  Fill(DataTable dt,  object  source)
    {
        
if  (source  ==   null )
            
throw   new  ArgumentException( " NothingNotValid " );

        
//  get the list of columns from the source
        List < string >  columns  =  GetColumns(source);
        
if  (columns.Count  <   1 return ;

        
//  create columns in DataTable if needed
         foreach  ( string  column  in  columns)
            
if  ( ! dt.Columns.Contains(column))
                dt.Columns.Add(column);

        
//  get an IList and copy the data
        CopyData(dt, GetIList(source), columns);
    }

 

这个方法所做的第一件事情就是从数据源中获得一个字段名字(通常是公共的属性域)的列表.是通过GetColumns()方法完成的.

接下来,代码对目标DataTable进行检查,确保它含有与从GetColumns()方法提取出来的每个字段名字相对应的字段.如果有任何字段没有找到,就将这些字段添加到DataTable中.最后就是源对象到DataTable的数据拷贝了。

 

GetColumns方法:

GetColumns()方法对源对象的类型进行判断,然后将具体工作分派给具体特定类型的工具方法:     

   private  List < string >  GetColumns( object  source)
    {
        List
< string >  result;
        
//  first handle DataSet/DataTable
         object  innerSource;
        IListSource iListSource 
=  source  as  IListSource;
        
if  (iListSource  !=   null )
            innerSource 
=  iListSource.GetList();
        
else
            innerSource 
=  source;

        DataView dataView 
=  innerSource  as  DataView;
        
if  (dataView  !=   null )
            result 
=  ScanDataView(dataView);
        
else
        {
            
//  now handle lists/arrays/collections
            IEnumerable iEnumerable  =  innerSource  as  IEnumerable;
            
if  (iEnumerable  !=   null )
            {
                Type childType 
=  GetChildItemType(
                  innerSource.GetType());
                result 
=  ScanObject(childType);
            }
            
else
            {
                
//  the source is a regular object
                result  =  ScanObject(innerSource.GetType());
            }
        }
        
return  result;
    }

  

接下来,代码会对该对象进行检查,看看它是不是一个DataView.如果是一个DataView,代码就会调用一个ScanDataView()方法来将字段的名字从DataView对象中剥离出来.

ScanDataView方法:   

   private  List < string >  ScanDataView(DataView ds)
    {
        List
< string >  result  =   new  List < string > ();
        
for  ( int  field  =   0 ; field  <  ds.Table.Columns.Count; field ++ )
            result.Add(ds.Table.Columns[field].ColumnName);
        
return  result;
    }
 

如果源对象不是DataView,但是却直接实现了IEnumerable接口的话,那么其子对象的类型将会被GetChildItemType()的方法提取出来.

GetChildItemType方法:

GetChildItemType()方法对子对象的类型进行检查,看看它是不是一个数组.如果是的话,它就会返回这个数组的元素类型---否则的话,它就会对listType的属性进行扫描来找到那个索引器:

///   <summary>
    
///  Returns the type of child object
    
///  contained in a collection or list.
    
///   </summary>
     public   static  Type GetChildItemType(Type listType)
    {
        Type result 
=   null ;
        
if  (listType.IsArray)
            result 
=  listType.GetElementType();
        
else
        {
            DefaultMemberAttribute indexer 
=
              (DefaultMemberAttribute)Attribute.GetCustomAttribute(
              listType, 
typeof (DefaultMemberAttribute));
            
if  (indexer  !=   null )
                
foreach  (PropertyInfo prop  in  listType.GetProperties(
                  BindingFlags.Public 
|
                  BindingFlags.Instance 
|
                  BindingFlags.FlattenHierarchy))
                {
                    
if  (prop.Name  ==  indexer.MemberName)
                        result 
=  GetPropertyType(prop.PropertyType);
                }
        }
        
return  result;
    }

 

索引器属性是可以被识别出来的,因为它有一个由编译器添加的[DefaultMember()]特性.如果代码找到了一个索引器,那么由这个索引器属性所返回的类型就被作为结果返回.如果数组和索引器的方法都失败了,那么就说明无法对子对象的类型进行判断,所以代码就返回null.

GetPropertyType方法:

   ///   <summary>
    
///  Returns a property's type, dealing with
    
///  Nullable <T>  if necessary.
    
///   </summary>
     public   static  Type GetPropertyType(Type propertyType)
    {
        Type type 
=  propertyType;
        
if  (type.IsGenericType  &&
          (type.GetGenericTypeDefinition() 
==   typeof (Nullable)))
            
return  type.GetGenericArguments()[ 0 ];
        
return  type;
    }
 

让我们再回到GetColumns()方法,代码调用了一个ScanObject()方法,用子对象的类型作为参数.ScanObject()用反射来处理类型.如果你能回忆起来的话,GetColumns()方法本身如果检测到源对象不是一个集合,而是一个单一复杂的Struct或对象的话也会调用ScanObject():

ScanObject()方法:

   private  List < string >  ScanObject(Type sourceType)
    {
        List
< string >  result  =   new  List < string > ();

        
if  (sourceType  !=   null )
        {
            
//  retrieve a list of all public properties
            PropertyInfo[] props  =  sourceType.GetProperties();
            
if  (props.Length  >=   0 )
                
for  ( int  column  =   0 ; column  <  props.Length; column ++ )
                    
if  (props[column].CanRead)
                        result.Add(props[column].Name);

            
//  retrieve a list of all public fields
            FieldInfo[] fields  =  sourceType.GetFields();
            
if  (fields.Length  >=   0 )
                
for  ( int  column  =   0 ; column  <  fields.Length; column ++ )
                    result.Add(fields[column].Name);
        }
        
return  result;
    }

 

在Fill()方法中的最后一步是通过对一个CopyData()方法的调用来将数据从源列表拷贝到DataTable中.从GetColumns()中返回的字段名字列表被作为参数传进这个方法,用来从源列表的每个条目中提出数据.

  private   void  CopyData(
      DataTable dt, IList ds, List
< string >  columns)
    {
        
//  load the data into the DataTable
        dt.BeginLoadData();
        
for  ( int  index  =   0 ; index  <  ds.Count; index ++ )
        {
            DataRow dr 
=  dt.NewRow();
            
foreach  ( string  column  in  columns)
            {
                
try
                {
                    dr[column] 
=  GetField(ds[index], column);
                }
                
catch  (Exception ex)
                {
                    dr[column] 
=  ex.Message;
                }
            }
            dt.Rows.Add(dr);
        }
        dt.EndLoadData();
    }
 

在对DataTable对象作任何修改之前,代码调用了它的BeginLoadData()方法,这就告诉了DataTable对象将要对它进行一批修改,以便于工作它可以暂时抑制一下它的正常的事件处理机制.这样做不仅仅使修改的过程更有效率,而且避免了UI因为DataTable的变化而进行刷新的问题.

随后,这个方法对源列表中的所有条目进行了遍历.代码会为每一个条目都创建一个新的DataRow对象,用源对象中的值进行赋值,最后将该DataRow添加到DataTable中.这个过程中的关键方法是GetField().

在所有的数据都被拷贝到DataTable中以后,它的EndLoadData()方法将会被调用,这个方法调用会告诉该对象这批修改已经完成,可以继续它正常的事件、索引和约束处理了.

GetField()方法:

真正为CopyData()做实际工作的是GetField()方法.这个方法负责将指定的字段属性或者域的值从源对象中提取出来.因为源对象可能是简单类型,也有可能是复杂类型.

private   static   string  GetField( object  obj,  string  fieldName)
    {
        
string  result;
        DataRowView dataRowView 
=  obj  as  DataRowView;
        
if  (dataRowView  !=   null )
        {
            
//  this is a DataRowView from a DataView
            result  =  dataRowView[fieldName].ToString();
        }
        
else   if  (obj  is  ValueType  &&  obj.GetType().IsPrimitive)
        {
            
//  this is a primitive value type
            result  =  obj.ToString();
        }
        
else
        {
            
string  tmp  =  obj  as   string ;
            
if  (tmp  !=   null )
            {
                
//  this is a simple string
                result  =  ( string )obj;
            }
            
else
            {
                
//  this is an object or Structure
                 try
                {
                    Type sourceType 
=  obj.GetType();

                    
//  see if the field is a property
                    PropertyInfo prop  =  sourceType.GetProperty(fieldName);

                    
if  ((prop  ==   null ||  ( ! prop.CanRead))
                    {
                        
//  no readable property of that name exists - 
                        
//  check for a field
                        FieldInfo field  =  sourceType.GetField(fieldName);
                        
if  (field  ==   null )
                        {
                            
//  no field exists either, throw an exception
                             throw   new  DataException( " NoSuchValueExistsException " + fieldName);
                        }
                        
else
                        {
                            
//  got a field, return its value
                            result  =  field.GetValue(obj).ToString();
                        }
                    }
                    
else
                    {
                        
//  found a property, return its value
                        result  =  prop.GetValue(obj,  null ).ToString();
                    }
                }
                
catch  (Exception ex)
                {
                    
throw   new  DataException( " ErrorReadingValueException " + fieldName, ex);
                }
            }
        }
        
return  result;
    }

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值