代码改变世界

Silverlight实现查询建模(八) 传递DataTable解决方案

2009-09-12 22:05  Amar-Yao  阅读(2279)  评论(1编辑  收藏  举报
  我们都知道Silverlight端不能直接使用DataTable,DataSet等数据存储。但某些情况下实体类的传递方式根本无法满足我们的需求。举个例子,在进行查询建模时我们根本不知道用户从哪张表选择字段,更有甚者我们还可能不知道用户从哪个数据源选择表(这个问题我通过SmartDAL的特性加以支持)。这种情况下我们无法建立实体类定义。这也是我使用C#,Java这些静态语言感觉最不爽的地方。动态语言中这种处理相当简单。
  我在XCenter中的实现思想就是Server端(WCF实现端)将SmartDAL取出的DataTable分为数据和元数据两部分存储并通过WCF端进行传递。在Silverlight端根据元数据信息动态生成并编译出动态实体类实例。并填充真实的待绑定集合。由于在Silverlight端动态生成并编译实体类的过程比较耗时所以在Silverlight端建立了缓存。并用元数据中的唯一Id进行标识。
  元数据定义在XCenter.Framework.Public.DataSetData命名空间。主要结构就是3个类。
  Field.cs 字段信息(部分定义)
Code
  MetaData.cs 元数据定义
 
Code

  DataSetData.cs 数据集定义
 
Code

 Field对应于DataTable中的列信息。MetaData主要就是对Field进行封装,并实现一些公共的操作方法。DataSetData封装了MetaData并用List<List<object>>存放具体数据。
  这里要说明一下,由于从DataTable取出的实际数据都是基本类型(int,string,byte[]...)等WCF中可以直接传递的数据。所以这里用List<List<object>>传递数据不会有问题。如果List中有用户定义类型,不在ServiceKnownType中事先声明,那么Silverlight端反序列化时会报错。
  以IQEObjectStorage这个WCF服务接口的GetData方法可以看出具体的WCF声明:
 
        [OperationContract]
        DSDReturnDataVO GetData(QueryBaseVO qbd, ServiceContext context);

  这里的DSDReturnDataVO只是XCenter中为所有能返回DataSetData的服务定义的统一的返回值。读者可以直接返回DataSetData。这个服务其实就是手工Sql设计的取数方法。其内部处理逻辑是将查询模型解析成Sql送到数据库执行并取得DataTable组装DataSetData。这里的具体逻辑我们暂时不关心。
  下面看看SL端对传来的DataSetData的处理过程。我们可以看QueryMain.xaml.cs的service_GetDataCompleted方法,这个方法最初是由工具栏中的运行查询按钮触发。
 
Code

  可以看到主要的处理逻辑被封装在DataSetData的扩展方法:ToDataSource()中,这里代码就不贴了,读者可以结合本贴看看里面的具体实现步骤。主要就是先在缓存中根据MetaData的唯一标识查找动态生成的类实例,如果没有找到那么就启动动态编译并把生成的实例加入缓存以备下次再用。要说一下的是这个缓存其实就是定义在App中的字典字段:
 
Code

   只不过通过WindowHelper进行了引用。WindowHelper.TempClassDic。
   最后要提醒读者,到这里这个解决方案并不完美,因为我们没有考虑数据量的问题。当数据量很大时WCF传递数据会有问题。我们可以将DataSetData中的List<List<object>>数据的形式改为Byte[]并进行压缩再传递(或者是JSON),这样的话SL端又多了一道加压缩的过程。但个人认为这并不是最完善的解决方法。最终突破数据量的问题可能最好的还是分块传递。可能用到WCF双向通讯的技术。这方面有经验的朋友可以分享一下经验。