Silverlight,WCF传递DataTable解决方案

原创|其它|编辑:郝浩|2009-09-17 10:59:44.000|阅读 1072 次

概述:Silverlight与WCF(WebService)交互多以实体类的形式进行数据传递。但对于报表平台这样的形式不可取,为你不能预知客户在设计报表时选中了哪个数据库的哪些表的哪些字段。因此传统.Net中的DataTable是一种很好解决方案。下面讨论笔者的一种解决方案。欢迎各位拍砖。

# 界面/图表报表/文档/IDE等千款热门软控件火热销售中 >>

      Silverlight与WCF(WebService)交互多以实体类的形式进行数据传递。但对于报表平台这样的形式不可取,为你不能预知客户在设计报表时选中了哪个数据库的哪些表的哪些字段。因此传统.Net中的DataTable是一种很好解决方案。下面讨论笔者的一种解决方案。欢迎各位拍砖。

      整个解决方案的思想就是将DataTable分为元数据(MetaData)、数据(Data)两部分进行传递。MetaData不用说就

是当前DataTable的列信息(例如列名,数据类型,最大长度等等)。至于数据,我们知道DataTable是一种二维结构。所以

我选择List<List<object>>的形式进行数据存储。这样的数据结构虽然效率不高但可扩展性比较强送到客户端后便于进一步

数据处理(例如:小记合计,动态列等)。MetaData,Data传递到客户端后客户端代码根据MetaData的信息用TypeBuilder等API

动态创建实体类,并转换为List<object>绑定到DataGrid。

      首先定义数据结构,这里我用DataSetData作为自定义的数据容器类。

      Field.cs 字段信息(对应DataTable中的列)


/// <summary>
    
/// 字段信息
    
/// </summary>

    [XCenter.Framework.Public.Serialization.Serializable,DataContract]
    
public class Field:XCenter.Framework.Public.Core.ICloneable,IMobileObject
    
{

        
public Field()
        

        }


        
props

        
public override string ToString()
        
{
            
return String.IsNullOrEmpty(caption) ? fieldName : caption;
        }


        
public override bool Equals(object obj)
        
{
            
if (fieldName == null || obj == null || !(obj is Field))
                
return false;
            Field f 
= (Field)obj;
            
return f.FiledName.Equals(fieldName);
        }


        
public override int GetHashCode()
        
{
            
return fieldName.GetHashCode();
        }


        
ICloneable 成员

        
IMobileObject 成员
    }

 

MetaData.cs 元数据信息(Field的容器)


/// <summary>
    
/// 元数据信息
    
/// </summary>

    [XCenter.Framework.Public.Serialization.Serializable,DataContract]
    
public class MetaData : XCenter.Framework.Public.Core.ICloneable,IMobileObject
    
{
        
prop

        
public

        
private

        
ICloneable 成员

        
IMobileObject 成员
    }

  DataSetData.cs 数据集定义信息(元数据、数据的容器)

 

 


/// <summary>
    
/// 数据集用于前后台传递数据
    
/// </summary>

    [XCenter.Framework.Public.Serialization.Serializable,DataContract]
    
public class DataSetData : XCenter.Framework.Public.Core.ICloneable,IMobileObject
    
{
        
prop

        
public virtual Field GetField(string fieldName)
        
{
            
if (md == null)
                
return null;
            
return md.GetField(fieldName);
        }


        
public virtual string[] GetFieldNames()
        
{
            
if(md == null)
                
return new string[]{};
            
return md.GetFieldNames();
        }



        
ICloneable 成员

        
IMobileObject 成员
    }

 

      以上是数据结构定义。还有两个核心转换方法DataTable 上的扩展方法GetData,该方法的主要作用是将DataTable的数据装入

DataSetData实例。


/// <summary>
        
/// 根据DataTable获得DataSetData对象
        
/// </summary>
        
/// <param name="dt"></param>
        
/// <returns></returns>
        public static DataSetData GetData(this DataTable dt)
        {
            DataSetData dsd 
= new DataSetData();
            MetaData md 
= new MetaData();
            
//提取元数据信息
            foreach (DataColumn col in dt.Columns)
            {
                Field f 
= new Field();
                f.Caption 
= col.Caption;
                f.DataType 
= col.DataType.ToString();
                f.Expression 
= col.Expression;
                f.FiledName 
= col.ColumnName;
                f.IsKey 
= col.Unique;
                f.IsReadOnly 
= col.ReadOnly;
                f.IsRequire 
= !col.AllowDBNull;
                f.MaxLength 
= col.MaxLength;
                md.AddField(f);
            }
            dsd.MetaData 
= md;
            
//装数据
            List<List<object>> datas = new List<List<object>>();
            
for (int i = 0; i < dt.Rows.Count; i++)
            {
                List
<object> rowData = new List<object>();
                
for (int j = 0; j < dt.Columns.Count; j++)
                {
                    rowData.Add(dt.Rows[i][j]);
                }
                datas.Add(rowData);
            }
            dsd.Datas 
= datas;
            
return dsd;
        }

 

      上面的方法在Server端运行。下面的方法在Client端运行,主要作用就是将List<List<object>>类型的数据根据元数据信息

生成实体类并填充到List<object>中供UI控件绑定。

      


public static class DataTableHelper
    
{
        
/// <summary>
        
/// 将DataSetData的数据转成SL绑定数据源
        
/// </summary>
        
/// <param name="dsd"></param>
        
/// <returns></returns>

        public static List<object> ToDataSource(this DataSetData dsd)
        
{
            
try
            
{
                
if (dsd == null || dsd.Datas == null || dsd.Datas.Count == 0)
                    
return new List<object>();
                Type targetType 
= null;
                
string className = dsd.MetaData.GetTempClassName();
                
if (!WindowHelper.TempClassDic.ContainsKey(className))
                
{
                    
//生成临时类
                    TypeBuilder tb = GetTypeBuilder(className);
                    ConstructorBuilder cBuilder 
= tb.DefineDefaultConstructor(
                        MethodAttributes.Public 
|
                        MethodAttributes.SpecialName 
|
                        MethodAttributes.RTSpecialName);
                    
foreach (Field f in dsd.MetaData.Fields)
                    
{
                        CreateProperty(tb, f.FiledName, Type.GetType(f.DataType));
                    }

                    targetType 
= tb.CreateType();
                    WindowHelper.TempClassDic.Add(className, targetType);
                }

                
else
                
{
                    
//临时类已经生成过,从缓存列表中得到
                    targetType = WindowHelper.TempClassDic[className];
                }

                
if (targetType == null)
                    
return new List<object>();
                
return GetDatas(targetType,dsd);
            }

            
catch (Exception ex)
            
{
                
throw new Exception("动态创建数据源实体类错误", ex);
            }

        }


        
/// <summary>
        
/// 填充数据
        
/// </summary>
        
/// <param name="targetType"></param>
        
/// <param name="datas"></param>
        
/// <param name="dsd"></param>
        
/// <returns></returns>

        private static List<object> GetDatas(Type targetType,DataSetData dsd)
        
{
            
try
            
{
                List
<object> resultList = new List<object>();
                MetaData md 
= dsd.MetaData;
                List
<List<object>> datas = dsd.Datas;
                
foreach (List<object> li in datas)
                
{
                    var instance 
= Activator.CreateInstance(targetType);
                    List
<Field> fields = md.Fields;
                    
for (int i = 0; i < fields.Count; i++)
                    
{
                        PropertyInfo p 
= targetType.GetProperty(fields[i].FiledName);
                        
if (p != null)
                        
{
                            p.SetValue(instance, li[i], 
null);
                        }

                    }

                    resultList.Add(instance);
                }

                
return resultList;
            }

            
catch (Exception ex)
            
{
                
throw new Exception("客户端填充数据错误", ex); //TODO:多语处理
            }

        }


        
/// <summary>
        
/// 获得TypeBuilder实例
        
/// </summary>
        
/// <param name="typeName"></param>
        
/// <returns></returns>

        private static TypeBuilder GetTypeBuilder(string typeName)
        
{
            
try
            
{
                
//XCenter.TempData
                AssemblyName an = new AssemblyName(DataConst.TempDataAssemblyName);
                AssemblyBuilder assemblyBuilder 
=
                    AppDomain.CurrentDomain.DefineDynamicAssembly(an,
                    AssemblyBuilderAccess.Run);
                
//TempMainModule
                ModuleBuilder moduleBuilder =
                    assemblyBuilder.DefineDynamicModule(DataConst.TempDataModuleName);
                TypeBuilder typeBuilder 
= moduleBuilder.DefineType(typeName,
                    TypeAttributes.Public 
|
                    TypeAttributes.Class 
|
                    TypeAttributes.AutoClass 
|
                    TypeAttributes.AnsiClass 
|
                    TypeAttributes.BeforeFieldInit 
|
                    TypeAttributes.AutoLayout, 
typeof(object));
                
return typeBuilder;
            }

            
catch (Exception ex)
            
{
                
throw new Exception("动态创建类型错误", ex);
            }

        }


        
private static void CreateProperty(TypeBuilder tb,string propertyName,
            Type propertyType)
        
{
            
try
            
{
                
if (tb == null ||
                    propertyType 
== null ||
                    String.IsNullOrEmpty(propertyName))
                
{
                    
throw new ArgumentException(":-> CreateProperty");
                }

                FieldBuilder fieldBuilder 
= tb.DefineField("_" + propertyName,
                    propertyType, FieldAttributes.Private);
                PropertyBuilder propertyBuilder 
=
                    tb.DefineProperty(
                        propertyName, PropertyAttributes.HasDefault, propertyType, 
null);
                MethodBuilder getPropMthdBldr 
=
                    tb.DefineMethod(
"get_" + propertyName,
                        MethodAttributes.Public 
|
                        MethodAttributes.SpecialName 
|
                        MethodAttributes.HideBySig,
                        propertyType, Type.EmptyTypes);
                ILGenerator getIL 
= getPropMthdBldr.GetILGenerator();
                getIL.Emit(OpCodes.Ldarg_0);
                getIL.Emit(OpCodes.Ldfld, fieldBuilder);
                getIL.Emit(OpCodes.Ret);
                MethodBuilder setPropMthdBldr 
=
                    tb.DefineMethod(
"set_" + propertyName,
                      MethodAttributes.Public 
|
                      MethodAttributes.SpecialName 
|
                      MethodAttributes.HideBySig,
                      
nullnew Type[] { propertyType });

                ILGenerator setIL 
= setPropMthdBldr.GetILGenerator();

                setIL.Emit(OpCodes.Ldarg_0);
                setIL.Emit(OpCodes.Ldarg_1);
                setIL.Emit(OpCodes.Stfld, fieldBuilder);
                setIL.Emit(OpCodes.Ret);

                propertyBuilder.SetGetMethod(getPropMthdBldr);
                propertyBuilder.SetSetMethod(setPropMthdBldr);
            }

            
catch (Exception ex)
            
{
                
throw new Exception("动态创建属性错误", ex);
            }

        }

    }

      

      不行了,代码贴太多了,速度太慢了,下一篇Blog再解释吧。(不知是cnblogs的问题还是遨游的问题)


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@evget.com

文章转载自:博客园

为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP