SilverLight从WCF也可以取到非实体集合的数据集

      现在做一个项目,在数据库和表名以及列名都不确定的情况下,返回查询的数据集。这在ASP.NET或者C/S模式很容易实现。但是在现有的SL+WCF技术下是不能实现的,首先返回值就不好确定,WCF的返回值类型必须是确定的。比较返回值为Object类型就不可以。而且返回DataTable和DataSet又不可以。在客户接收不到数据,返回的数据类型为Object。那么我们可以通过普通的方式取得数据集,然后把数据集转换为XML格式的字符串,然后在客户端把字符串解析为类型DataSet数据集。
     其实把DataSet数据集转化为XML格式的字符串以及把XML格式的字符串解析为DataSet数据集的工作,已经有加拿大的同行把业务逻辑封装好了,我们只要调用其中的方法就可以了,你也可以反编译看看老外的代码,老外的原文地址: http://silverlightdataset.net/silverlightdataset/Default.aspx,其中用到的组件为Silverlight.DataSetConnector.dll(服务端使用)和Silverlight.DataSet.dll(用于客户端)
    下面是服务端的程序


/// <summary>
/// 取得数据集
/// </summary>
/// <param name="strDataBase">服务器名称</param>
/// <param name="strDataTable">表名</param>
/// <param name="data">XML格式</param>
/// <param name="page">当前分页</param>
/// <param name="pageCount">分页总数</param>
/// <param name="strTableKeys">表主键</param>
/// <param name="strTableOrder">排列字段</param>
/// <returns></returns>
public string GetAllOriginalMetaData(string strDataBase, string strDataTable, string data, int page, out int pageCount,string strTableKeys,string strTableOrder)
{
pageCount = 0;
try
{
DataSet dataSet = Connector.FromXml(data);
//由于数据库和数据表的不确定性,所以不用LINQ,直接访问数据库
using (SqlConnection sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["MetadataConnectionString"].ConnectionString))
{
try
{
//判断连接是否打开
if (sqlConnection.State == ConnectionState.Closed)
{
sqlConnection.Open();
}
string strTable = strDataBase + ".dbo." + strDataTable;
//判断是否第一次加载数据,如果是,则获取总页数
if (page == -1)
{
string strsql = "SELECT Count(*) as Rowscount FROM " + strTable;
SqlCommand scCount = new SqlCommand(strsql, sqlConnection);
pageCount = Convert.ToInt32(scCount.ExecuteScalar());
page+=2;
}

SqlCommand sc = new SqlCommand();
//使用存储过程
sc.CommandType = CommandType.StoredProcedure;
//存储过程名
sc.CommandText = "PrcPager";
sc.Connection = sqlConnection;

//存储过程参数
SqlParameter[] parameters = {
new SqlParameter("@currPage", SqlDbType.Int,4),//当前页
new SqlParameter("@tabName",SqlDbType.NVarChar,2000),//表名
new SqlParameter("@ascColumn",SqlDbType.NVarChar,100),//排序字段
new SqlParameter("@bitOrderType",SqlDbType.Bit),
new SqlParameter("@pkColumn",SqlDbType.NVarChar,100)//主键字段
};
parameters[0].Value = page;

parameters[1].Value = strTable;

parameters[2].Value = strTableOrder;

parameters[3].Value =1;

parameters[4].Value = strTableKeys;

sc.Parameters.AddRange(parameters);

SqlDataAdapter sqlDataAdapter = new SqlDataAdapter();
sqlDataAdapter.SelectCommand = sc;
sqlDataAdapter.Fill(dataSet, "TableName");
//返回XML格式的字符串数据
return Connector.ToXml(dataSet);
}
catch (Exception e)
{
AccessLog.WriteLog(e.Message);
return null;
}
finally
{
sqlConnection.Close();
}
}
}
catch (Exception e)
{
//AccessLog.WriteLog(e.Message);
return null;
}
}
      由于返回的集合是以XML格式的字符串,所以如果数据量太大时,可以要占用大量的带宽,也可能会超时。所以使用分页,每次返回的数据集为当前的数据集。
     下面是分页存储过程

IF EXISTS(SELECT Name FROM SYSOBJECTS WHERE Name='PrcPager' AND TYPE='P')
DROP PROCEDURE PrcPager
GO
CREATE PROCEDURE PrcPager
-- 获得某一页的数据 --
@currPage int = 1, --当前页页码 (即Top currPage)
@showColumn varchar(2000) = '*', --需要得到的字段 (即 column1,column2,......)
@tabName varchar(2000), --需要查看的表名 (即 from table_name)
@strCondition varchar(2000) = '', --查询条件 (即 where condition......) 不用加where关键字
@ascColumn varchar(100) = '', --排序的字段名 (即 order by column asc/desc)
@bitOrderType bit = 0, ---排序的类型 (0为升序,1为降序)
@pkColumn varchar(100) = '', --主键名称
@pageSize int = 20 --分页大小
AS
BEGIN -- 存储过程开始
-- 该存储过程需要用到的几个变量
DECLARE @strSql varchar(4000) --该存储过程最后执行的语句
DECLARE @strOrderType varchar(1000) --排序类型语句 (order by column asc或者order by column desc)
BEGIN
IF @bitOrderType = 1 -- bitOrderType=1即执行降序
BEGIN
SET @strOrderType = ' ORDER BY '+@ascColumn+' DESC'
END
ELSE
BEGIN
SET @strOrderType = ' ORDER BY '+@ascColumn+' ASC'
END
IF @currPage = 1 -- 如果是第一页
BEGIN
IF @strCondition != ''
SET @strSql = 'SELECT TOP '+STR(@pageSize)+' '+@showColumn+' FROM '+@tabName+
' WHERE '+@strCondition+@strOrderType
ELSE
SET @strSql = 'SELECT TOP '+STR(@pageSize)+' '+@showColumn+' FROM '+@tabName+@strOrderType
END
ELSE -- 其他页
BEGIN
IF @strCondition !=''
SET @strSql ='select top '+str(@pageSize)+' '+@showColumn+' from (select top '+str(@currPage*@pageSize)+@showColumn+' from '
+@tabName+' WHERE ('+@strCondition+') '+@strOrderType+') as temp where '+@pkColumn+' not in (SELECT TOP '+STR((@currPage-1)*@pageSize)
+' '+@pkColumn+ ' FROM '+@tabName+' WHERE ('+@strCondition+') ' +@strOrderType+')'
ELSE
SET @strSql ='select top '+str(@pageSize)+' '+@showColumn+' from (select top '+str(@currPage*@pageSize)+@showColumn+' from '+@tabName+@strOrderType+') as temp'
+' where '+@pkColumn+' not in (SELECT TOP '+STR((@currPage-1)*@pageSize)+' '+@pkColumn+ ' FROM '+@tabName+@strOrderType+')'
END
END
EXEC (@strSql)
--print @strSql
END -- 存储过程结束
GO

       下面就来介绍客户端。其实按照加拿大的老兄的代码很简单,只要使用下面的代码就可以了

a) Add reference to Silverlight.DataSet.dll from Silverlight Application project and “using” directive to your page:

using Silverlight;



b) Create Silverlight DataSet and send it to server;

DataSet dataSet = new DataSet();

// Cretate DataTables, DataColumns, and add DataRows ...

// Use your knowledge about ADO.Net DataSet for this task



// Call WCF service

proxy.ProcessRequestAsync(dataSet.ToXml(true));


c) Receive response from server:
void proxy_ProcessRequestCompleted(object sender, ProcessRequestCompletedEventArgs e)

{

// Create Silverlight DataSet from xml string

DataSet dataSet = new DataSet();

dataSet.FromXml(e.Result);



// Process server response here

}
        但是SL的DataGrid不接受DATASET或者DataTable类型的数据源的,他接受的是实休集合。所以我们就需要扩展SL的DataGrid,使其变为像ASP.NET中的DataView那样,有DataSource属性,有DataBind方法。这个有源代码可以下载,你可以根据自己的需要再来扩展。下载地址为: http://slbindabledatagrid.codeplex.com/,其实这个方法的核心还是要把数据集转化为List类型的集合,然后这个结果再赋值给DataGrid.
      所以我要实现的方法,就是先用加拿大的同行的方法把XML格式的字符串解析成他的DataSet,然后再把这个DataSet的值变成扩展DataGrid的类型的DataSet。下面请看详细代码



public void GetAllFOrigialMetaData(string strDataBase, string strDataTable,string strDataTableKeys,string strDataTableOrder,int pageindex)
{
DataSet dataSet = new DataSet();
//客户端类
MetadataServiceClient msc = new MetadataServiceClient();
msc.Endpoint.Address = Utility.ProcessServiceAddress(msc.Endpoint.Address);
msc.GetAllOriginalMetaDataCompleted += new EventHandler<GetAllOriginalMetaDataCompletedEventArgs>(
(o, e) =>
{
DataSet dataSets = new DataSet();
//使用接口把服务端传的数据解析为DataSet数据集
dataSets.FromXml(e.Result);
ds = dataSets;
_pageCount = e.pageCount;
if (OnCompleted != null)
{
OnCompleted();
}
OnCompleted = null;
}
);
msc.GetAllOriginalMetaDataAsync(strDataBase, strDataTable, dataSet.ToXml(true), pageindex, strDataTableKeys, strDataTableOrder);
}


   /// <summary>
        /// 初始化数据
        /// </summary>
        /// <param name="pageindex">当前页码,为-1时,表示第一次加载数据</param>
        private void InitData(int pageindex)
        {
            Windows ws = new Windows(this.FindName("waiting") as Waiting);
            Windows.ShowWaitingOfChild();
            //把参数转化为数组
            string[] arr = Convert.ToString(Tag).Split('|');
            FOrigialMetaData fomd = new FOrigialMetaData();
            fomd.OnCompleted += new FOrigialMetaData.OnComplete(
                () =>
                {
                    string strcaption = string.Empty;
                    //初始化扩展的DataTable
                    Data.DataTable dt = new Data.DataTable("MyDataTable");
                    fomd.OnCompletedCols += new FOrigialMetaData.OnComplete(
                        () =>
                        {
                            //列数据集合
                            _list = fomd.List;
                            string str="varchar";
                            //根据原始数据的列初始化变量dt的列
                            foreach (Silverlight.DataColumn dc in fomd.FOrigialMetaDataSet.Tables[0].Columns)
                            {
                                List<tbDataColumns> tdc=null;
                                //如果列集合存在
                                if (_list.Count > 0)
                                {
                                    tdc = _list.Where(t => t.cnvcColumnEName == dc.ColumnName).ToList<tbDataColumns>();
                                    //查找的列不存在,则继续
                                    if (tdc.Count==0)
                                        continue;
                                    //赋值中文列名及类型
                                    strcaption = tdc.ElementAt(0).cnvcColumnName;
                                    str = tdc.ElementAt(0).cnvcDataType;
                                }
                                else //不存在列集合
                                {
                                    strcaption = dc.ColumnName;
                                }
                                Data.DataColumn dcchild = new HIEG2.Portal.Data.DataColumn(dc.ColumnName, strcaption, true, true, true, true, str);
                                dt.Columns.Add(dcchild);
                            }
                            //复制每一行的数据
                            foreach (Silverlight.DataRow dr in fomd.FOrigialMetaDataSet.Tables[0].Rows)
                            {
                                Data.DataRow drchild = new HIEG2.Portal.Data.DataRow();
                                foreach (Data.DataColumn dc in dt.Columns)
                                {
                                    //当数据类型为DateTime时,需要格式化为yyyy-MM-dd HH:mm:ss
                                    if (dc.strDataType.ToLower() == "datetime")
                                    {
                                        if (Convert.ToString(dr[dc.ColumnName]) != "")
                                            drchild[dc.ColumnName] = Convert.ToDateTime(dr[dc.ColumnName]).ToString("yyyy-MM-dd HH:mm:ss");
                                        else
                                            drchild[dc.ColumnName] = "";
                                        continue;
                                    }
                                    drchild[dc.ColumnName] = dr[dc.ColumnName];
                                }
                                dt.Rows.Add(drchild);
                            }
                            Data.DataSet ds = new Data.DataSet("MyDataSet");
                            ds.Tables.Add(dt);
                            //把数据源赋值给表格集合
                            radGridView.DataSource = ds;
                            radGridView.DataMember = "MyDataTable";
                            //绑定数据
                            radGridView.DataBind();
                            //第一次加载时,需要设置分页
                            if (pageindex == -1)
                            {
                                radDataPager.BindSource(fomd.PageCount, PageSize);
                                radDataPager.PageIndexChanged -= new EventHandler<EventArgs>(dpEmployee_PageIndexChanged);
                                radDataPager.PageIndexChanged += new EventHandler<EventArgs>(dpEmployee_PageIndexChanged);
                            }
                            Windows.HideWaitingOfChild();
                        }
                        );
                    fomd.GetAllOrigialMetaDataCols(arr[0]);
                    
                }
                );
            //取得当前页的原始数据
            fomd.GetAllFOrigialMetaData(arr[1], arr[2],arr[3],arr[4],pageindex);
        }
        void dpEmployee_PageIndexChanged(object sender, EventArgs e)
        {
            InitData(radDataPager.PageIndex+1);
        }
    }
        通过上面的方法,其实上可以实现在不确定数据库和数据表的情况下,SL端从WCF取得数据集。不过还有一个地方需要扩展,那就是DataPager,具体的实现,请看: http://www.cnblogs.com/xiaozhuang/archive/2009/08/17/1548129.html,其实我的代码中也已经有实现,下面是主要的代码,用于扩展 DataPager
      
public static class DataPageExtension
{
public static void BindSource(this DataPager dataPager, int totalCount, int pageSize)
{
List<int> list = new List<int>(totalCount);
for (int i = 0; i < totalCount; i++) list.Add(i);
PagedCollectionView pcv = new PagedCollectionView(list);
pcv.PageSize = pageSize;
dataPager.Source = pcv;
}
}
       好了,今天就写到这了,有什么问题,大家可以一块交流,如果写的有不足之处,请指出。



你可能感兴趣的:(silverlight)