• 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;
    }
    }
           好了,今天就写到这了,有什么问题,大家可以一块交流,如果写的有不足之处,请指出。



  • 相关阅读:
    学习进度——第五周
    构建之法阅读笔记02
    学习进度——第四周
    整型数组——首尾相连
    构建之法阅读笔记01
    二维数组
    学习进度——第三周
    新最大子数组——数量级和数量无限大
    最大子数组求和
    P3388 【模板】割点(割顶)题解 tarjan求割点
  • 原文地址:https://www.cnblogs.com/888h/p/1852543.html
Copyright © 2020-2023  润新知