PivotTable_OWC+AnalysisService+Asp.net4.0构建OLAP应用的解决方案

本文详细介绍了如何使用OWC、AnalysisService和Asp.net4.0构建OLAP应用,包括AnalysisServices的配置、Asp.net代码开发、前端PivotTable开发及CellSet到DataTable的转换方法。提供了从AnalysisServices查询数据并展示为PivotTable的完整流程,适合对OLAP应用感兴趣的程序员共享。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        最近,为了完成公司的业务要求,除了使用ReportService开发普通的rdl报表,和使用VS2010自带的报表开发工具开发rdlc报表外,还需要使用OWC+AnalysisService来满足一些客户的特殊需求,特别是需要使用OWC的PivotTable和ChartSpace开发,于是我在最近查阅了很多的网上的资料,整理出了一套基于:OWC+AnalysisService+Asp.net4.0构建OLAP应用解决方案,希望Share在这里与有这方面兴趣的程序猿们共享。(其中还有不足之处,希望多多指教)。
要想正确的使用该解决方案,需要处理好以下几方面。
一、AnalysisServices的配置
首先先说一下我是用的开发工具:Asp.net的开发使用的是VS2010,数据库使用的是SqlServer2008 R2,AnalysisServices使用的是SqlServer2008 R2自带的BI开发工具:SQL Server Bussiness Intelligence Development Studio。
1.配置步骤如下:打开SQL Server Bussiness Intelligence Development Studio:

2.选择文件->新建->新建项目:选择Analysis Services项目:

这时就会在解决方案资源管理器里边出现以下文件:

3.然后依次:新建数据源,新建视图,新建多维数据集……(此处不再详细介绍)关于Analysis Services的相关使用知识,请参阅MSDN:Analysis Services 向导
好了,现在就把Analysis Services 建好了 :


接下来,右键点击AnalysisServicesTestProject,点击部署即可,部署成功后,就可以做接下来的步骤了。
二、VS2010中开发Asp.net代码
打开VS2010,新建我们的OLAP的Web部分了,在VS2010下新建如下的解决方案:AnalysisServices,解决方案下边依次有Application,Common,Service等几个项目文件,当然,这里不一定必要这样子,你可以根据自己的实际需要创建项目,我这里只是一个简单的Demo。

其中Model层主要创建的是一些实体类,ServiceImp层主要实现的数据的访问,这里边又分为数据访问层Persistence和业务逻辑层Provider:

其中Config文件夹里边是一个连接字符串的实体类。Analysis Services的连接字符串如下:

public static readonly string AnalysisServicesConn = "Datasource=localhost;Initial Catalog=AnalysisServicesTestProject";//注意是多维数据集
好了,现在就可以进行Analysis Services的数据访问了,在这里我要讲述一下AnalysisServices的一个专用的数据访问动态链接库ADOMD.NET,参考( ADOMD.NET 客户端编程你可以添加引用到你的VS项目。
引用名称:Microsoft.AnalysisServices.AdomdClient。

应用文件位置:C:\Program Files (x86)\Microsoft.NET\ADOMD.NET\100\Microsoft.AnalysisServices.AdomdClient.dll。

现在就可以编写你的数据访问程序了,为了做一个示例,下面我简单的写了一个,写的很粗糙,仅供参考:

 /// <summary>
        /// 获取AdminUser信息
        /// </summary>
        /// <returns></returns>
        public static CellSet GetAdminUserCellSetMsg()
        {
            string sql = @"select [BI Admin User].[User Name].children on columns,{[BI Admin User].[User Real Name].children} on rows from [BI Report Center]";
            AdomdConnection conn = new AdomdConnection(AnalysisServicesConfig.AnalysisServicesHttpConn2);
            try
            {
                conn.Open();
                AdomdCommand comm = new AdomdCommand(sql, conn);
                CellSet cs = comm.ExecuteCellSet();
                return cs;
            }
            catch (Exception e)
            {
                throw e;
            }
            finally
            {
                conn.Close();
            }
        }


其中的黑体字部分就是传说中的MDX查询语句,它跟T-SQL语句有类似之处,但是有很大的不同,关于MDX查询语句请参考: MDX 语句参考

三、前端PivotTable的开发介绍:
PivotTable是一个客户端数据钻取控件。你需要在你的前端页面里边写上这样的一段代码:

<img src="http://hi.youkuaiyun.com/attachment/201108/15/0_1313392793D5jz.gif" alt="" />


客户端代码实现:

<object id="PivotTable1" classid="CLSID:0002E55A-0000-0000-C000-000000000046"></object>
 <script language="javascript" type="text/javascript">
        window.onload = LoadPage;
        var SEP = "/,/";
        var SEP2 = "/,,/";
    
        //初始化报告参数
        //TODO:这里为了做成通用的报告,变量名称需要变更
        //需要添加到行区域的字段名称集合,以Common.SEP分割
        var strRowFieldNames = "<%=Server.UrlDecode(Request.QueryString["RowFieldNames"])%>";
        //需要添加到列区域的字段名称集合,以Common.SEP分割
        var strColumnFieldNames = "<%=Server.UrlDecode(Request.QueryString["ColumnFieldNames"])%>";
        //过滤字段名称集合,以Common.SEP分割
        var strFilterFieldNames = "<%=Server.UrlDecode(Request.QueryString["FilterFieldNames"])%>";
        //需要进行分段汇总的字段名称
        //格式为:字段名/,,/分组类型/,,/起始值/,,/间隔值/,/第二个分组
        //其中/,,/为Common.SEP2, /,/为Common.SEP
        var strGroupFieldNamesAndValues = "<%=Server.UrlDecode(Request.QueryString["GroupFieldNamesAndValues"])%>";

        //图表类型
        var intChartType = parseInt("<%=Server.UrlDecode(Request.QueryString["ChartType"])%>");

        //声明变量,用来存储页面上的OWC Object
        //透视表对象及透视表的常量对象
        var pvt, pvtconstants;
    
        //图表对象及图标的常量对象
        var cht, chtconstants;

       function LoadPage()
        {
            //初始化透视表
            InitPivotTable();
        }
        /**
         * 初始化透视表
         */
        function InitPivotTable()
        {
            //声明RecordSet对象
            var adors = new ActiveXObject("ADODB.Recordset");
        
            //声明XMLDocument对象
            //TODO:msxml2.domdocument有可能是msxml3.domdocument或msxml4.domdocument,有待证明
            var xmldoc = new ActiveXObject("msxml2.domdocument");
        
            //服务器端返回的XML字符串,用来构造RecordSet
            var str="<%=xml%>";
        
            //XMLDocument对象加载XML字符串
            xmldoc.loadXML(str);
        
            //RecordSet设定数据源为上面的XMLDocument对象,并打开
            adors.Open(xmldoc);

            pvt = document.PivotTable1;
        
            pvtconstants = pvt.Constants;
            //设定透视表的数据源为上面的RecordSet对象
            pvt.DataSource = adors;
        
            //设定透视表的一些属性,具体请参考OWC For VBA
            pvt.AutoFit = true;
            pvt.DisplayToolbar = true;
            pvt.DisplayExpandIndicator = true;
            pvt.DisplayAlerts = true;
            pvt.DisplayBranding = true;
            pvt.DisplayDesignTimeUI = true;
            pvt.DisplayFieldList = true;
            pvt.DisplayOfficeLogo = false;
            pvt.DisplayPropertyToolbox = false;
            pvt.DisplayScreenTips = true;

            pvt.ActiveView.TitleBar.Visible = true;
            pvt.ActiveView.TitleBar.Caption = "<%=title%>";
            pvt.ActiveView.TitleBar.Font.Name = "arial";
            pvt.ActiveView.TitleBar.Font.Size = 10;

            pvt.ActiveView.TotalBackColor = "CornSilk";
            pvt.ActiveView.TotalFont.Name = "arial";
            pvt.ActiveView.TotalFont.Size = 8;
            pvt.ActiveView.FieldLabelFont.Name = "arial";
            pvt.ActiveView.FieldLabelFont.Size = 8;
            pvt.ActiveView.HeaderFont.Name = "arial";
            pvt.ActiveView.HeaderFont.Size = 8;
            pvt.ActiveView.PropertyCaptionFont.Name = "arial";
            pvt.ActiveView.PropertyCaptionFont.Size = 8;
            pvt.ActiveView.PropertyValueFont.Name = "arial";
            pvt.ActiveView.PropertyValueFont.Size = 8;
            pvt.ActiveView.ExpandMembers = pvtconstants.plExpandNever;
            pvt.ActiveView.ExpandDetails = pvtconstants.plExpandNever;
        
            //设定每一个字段的字体,字号,颜色等
            for(var i = 0; i <= pvt.ActiveView.FieldSets.Count - 1; i++)
            {
                 pvt.ActiveView.FieldSets(i).Fields(0).DetailFont.Name = "arial";
                 pvt.ActiveView.FieldSets(i).Fields(0).DetailFont.Size = 8;
                 pvt.ActiveView.FieldSets(i).Fields(0).GroupedFont.Name = "arial";
                 pvt.ActiveView.FieldSets(i).Fields(0).GroupedFont.Name = "arial";
                 pvt.ActiveView.FieldSets(i).Fields(0).GroupedFont.Size = 8;
                 pvt.ActiveView.FieldSets(i).Fields(0).SubtotalLabelFont.Name = "arial";
                 pvt.ActiveView.FieldSets(i).Fields(0).SubtotalLabelFont.Size = 8;
                 pvt.ActiveView.FieldSets(i).Fields(0).SubtotalFont.Name = "arial";
                 pvt.ActiveView.FieldSets(i).Fields(0).SubtotalFont.Size = 8;
                 pvt.ActiveView.FieldSets(i).Fields(0).SubtotalBackColor = "LightSteelBlue";
            }
                
            //将所有字段都添加到”过滤”区域
            for(var i = 0; i < pvt.ActiveView.FieldSets.Count; i++)
            {
                pvt.ActiveView.FilterAxis.InsertFieldSet(pvt.ActiveView.FieldSets(i));
            }
                
            /*
                * 添加一个”合计”字段
                * AddTotal方法原型: AddTotal(Name, Field, Function)
                * Name合计字段的名字
                * Field需要进行合计的列对象
                * Function合计方法
                */
            var ctotal = pvt.ActiveView.AddTotal("汇总", pvt.ActiveView.FieldSets(0).Fields(0), pvtconstants.plFunctionCount);
            /*
            * 将”合计”字段添加到”数据区域”
            * InsertTotal方法原型: InsertTotal(Total, Before)
            * Total是一个PivotTotal类型的对象,也就是上面声明的对象
            * Bebore是指定要在其之前插入总计的总计索引。如果不指定该参数,则总计插入到集合的末尾。
            */
            pvt.ActiveView.DataAxis.InsertTotal(ctotal, 0);
 
            //设定列区域
            SetColumnFields();
                
            //设定明细区域
            SetDataFields();
                
            //设定分组
            SetGroupFields();
            /*
            * 隐藏指定对象的明细单元格。
            * 如果指定对象为 PivotData 对象,将隐藏所有明细单元格。
            * 如果指定对象为 PivotRowMember 对象,将隐藏该行的所有明细单元格。
            * 如果指定对象为 PivotColumnMember 对象,将隐藏该列的所有明细单元格。
            */
            pvt.ActiveData.HideDetails();
        }
    
        //设定行区域
        function SetRowFields()
        {
            if(strRowFieldNames == "")
            {
                return;
            }
                
            var OrgCollection = strRowFieldNames.split(SEP);
                
            //循环要显示在行上的字段
            for(var i = 0; i < OrgCollection.length; i++)
            {
                pvt.ActiveView.FieldSets(OrgCollection[i]).Fields(0).IsIncluded = true;
                    pvt.ActiveView.RowAxis.InsertFieldSet(pvt.ActiveView.FieldSets(OrgCollection[i]));
            }
         }
        
        //设定列区域
        function SetColumnFields()
        {
            if(strColumnFieldNames == "")
                {
                    return;
                }
                
                var ColumnFieldsCollection = strColumnFieldNames.split(SEP);
                
                for(var i = 0; i < ColumnFieldsCollection.length; i++)
                {
                    pvt.ActiveView.FieldSets(ColumnFieldsCollection[i]).Fields(0).IsIncluded = true;
            pvt.ActiveView.ColumnAxis.InsertFieldSet(pvt.ActiveView.FieldSets(ColumnFieldsCollection[i]));
                }
        }
        
        //设定数据明细区域
        function SetDataFields()
        {
            var ColumnFieldsCollection = strColumnFieldNames + SEP + strRowFieldNames + SEP + strFilterFieldNames + SEP;
            for(var i = 0; i < pvt.ActiveView.FieldSets.Count; i++)
                {
                    if(ColumnFieldsCollection.indexOf(pvt.ActiveView.FieldSets(i).Name + SEP) == -1)
                    {
                        pvt.ActiveView.DataAxis.InsertFieldSet(pvt.ActiveView.FieldSets(i));
                    }
                }
        }
        
        //设定字段分组
        function SetGroupFields()
        {
            //得到分组字段定义的数组,数组的每个元素是字段分组的一个完整定义
            var GroupCollection = strGroupFieldNamesAndValues.split(SEP);
            
            for(var i = 0; i < GroupCollection.length; i++)
            {
                if(GroupCollection[i] == "")
                {
                    break;
                }
                
                //得到其中的一个字段分组定义
            var OneGroupDefination = GroupCollection[i].split(SEP2);
            
            if(OneGroupDefination.length != 4)
            {
                break;
            }
            
            //字段名称
            var FieldName = OneGroupDefination[0];
            //分组类型
            var GroupMethod = parseInt(OneGroupDefination[1]);
            //基数
            var BaseAmount = parseFloat(OneGroupDefination[2]);
            //间隔值
            var IntervalAmount = parseFloat(OneGroupDefination[3]);
            
            if(IntervalAmount == 0)
                {
                        pvt.ActiveView.FieldSets(FieldName).Fields(0).GroupOn = pvtconstants.plGroupOnEachValue;
                }
                else
                {
                        pvt.ActiveView.FieldSets(FieldName).Fields(0).GroupOn = GroupMethod;
                        pvt.ActiveView.FieldSets(FieldName).Fields(0).GroupInterval = IntervalAmount;
                        pvt.ActiveView.FieldSets(FieldName).Fields(0).GroupStart = BaseAmount;
                }
            }
        }

 </script>

Asp.net后台代码:首先需要引用OWC11
引用:Microsoft Office Web Components 11.0
DLL文件(引用文件)位置:C:\Windows\assembly\GAC\Microsoft.Office.Interop.Owc11\11.0.0.0__71e9bce111e9429c\Microsoft.Office.Interop.Owc11.dll

 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Beisen.BIReportCenter.Model;
using System.Data;
using Beisen.AnalysisServices.Utility;
using System.IO;
using System.Xml;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.Office.Interop;
using AnalysisServices.Model.CustomEntity; 
namespace AnalysisServices.UI.Admin
{
    public partial class PivotTableExample : System.Web.UI.Page
    {
     
        private string _xml;
        public string xml
        {
            get{return _xml;}
            set{_xml = value;}
        }
        private string _title;
        public string title
        {
            get { return _title; }
            set { _title = value; }
        }
        protected void Page_Load(object sender, EventArgs e)
        {
            SetXmlValueByAnalysisServices();
        }
       private void SetXmlValueByAnalysisServices()
        {
            CellSet cs = Beisen.AnalysisServices.ServiceImp.Provider.BIAdminUserProvider.Instance.GetAdminUserCellSetMsg();
            DataTable dt = CellSetToDataTable.ToDataTable(cs);
            dt.TableName = "AdminUser";
            this._xml = ConvertToXML.ConvertDataTableToXML(dt);
            this._title = "数据报表";
        }
    }
}

 其中还需要注意的是,我们从AnalysisServices 里边查询出来的数据,只是一个CellSet,不是我们传统的数据表DataTable,我们需呀进行CellSet到数据表之间的转换: 

关于CellSet转DataTable的改进方案
下边该说说 ConvertDataTableToXML方法了:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Text.RegularExpressions;

namespace AnalysisServices.Utility
{
  public  class ConvertToXML
    {
        /// <summary>
        /// 将DataTable转换成RecordXML函数
        /// </summary>
        /// <param name=“dt”>要转换的DataTable</param>
        /// <returns>转换好的XML字符串</returns>
        public static string ConvertDataTableToXML(DataTable dt)
        {
            /*DataTable支持的数据类型
                             system.int64
                             system.byte[]
                             system.boolean
                             system.string
                             system.datetime
                             system.decimal
                             system.double
                             system.int32
                             system.single
                             system.int16
                             system.object
                             system.byte
                             system.guid
                      */
            string TempValue;

            for (int i = 0; i < dt.Columns.Count; i++)
            {
                TempValue = dt.Columns[i].ColumnName;
                Regex rex = new Regex("\\W");
                TempValue = rex.Replace(TempValue, "");

                rex = new Regex("^\\d");
                if (rex.Replace(TempValue, "").Length != TempValue.Length)
                {
                    TempValue = "N" + TempValue;
                }
                dt.Columns[i].ColumnName = TempValue;
            }

            StringBuilder sb = new StringBuilder();

            sb.Append("<xml xmlns:s='uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882' ");
            sb.Append("xmlns:dt='uuid:C2F41010-65B3-11d1-A29F-00AA00C14882' ");
            sb.Append("xmlns:rs='urn:schemas-microsoft-com:rowset' ");
            sb.Append("xmlns:z='#RowsetSchema'> ");
            sb.Append("<s:Schema id='RowsetSchema'> ");
            sb.Append("<s:ElementType name='row' content='eltOnly' rs:CommandTimeout='30'> ");

            for (int i = 0; i < dt.Columns.Count; i++)
            {
                string DataType;
                switch (dt.Columns[i].DataType.ToString().ToLower())
                {
                    case "system.boolean":
                        DataType = "string";
                        break;

                    case "system.byte":
                    case "system.int16":
                    case "system.int32":
                    case "system.int64":
                        DataType = "int";
                        break;

                    case "system.decimal":
                    case "system.double":
                    case "system.single":
                        DataType = "float";
                        break;

                    case "system.string":
                        DataType = "string";
                        break;
                    case "system.datetime":
                        DataType = "datetime";
                        break;

                    default:
                        throw new ArgumentException();
                }
                sb.Append("<s:AttributeType name='" + dt.Columns[i].ColumnName + "' rs:number='" + (i + 1).ToString() + "' rs:writeunknown='true'> ");
                sb.Append("<s:datatype dt:type='" + DataType + "' dt:maxLength='100' rs:maybenull='true' /> ");
                sb.Append("</s:AttributeType> ");
            }

            sb.Append("<s:extends type='rs:rowbase' /> ");
            sb.Append("</s:ElementType> ");
            sb.Append("</s:Schema> ");
            sb.Append("<rs:data> ");

            for (int i = 0; i < dt.Rows.Count; i++)
            {
                sb.Append("<z:row ");
                for (int j = 0; j < dt.Columns.Count; j++)
                {
                    TempValue = dt.Rows[i][j].ToString().Replace("<", "").Replace(">", "").Replace("'", "").Replace("\"", "");

                    if (dt.Columns[j].DataType.ToString().ToLower() == "system.datetime" && TempValue == string.Empty)
                    {
                        //TempValue = INVALIDDATE.ToString(DATEMASK);
                        TempValue = "";
                    }
                    sb.Append(dt.Columns[j].ColumnName + "='" + TempValue + "' ");
                }
                sb.Append("/> ");
            }
            sb.Append("</rs:data> ");
            sb.Append("</xml> ");
            return sb.ToString();
        }

    }
}


开发结果展示:

讲到这里,想必你已经对OWC+AnalysisService+Asp.net4.0构建OLAP应用有一定的了解了吧。
由于时间关系,我介绍的比较粗糙,很多东西还没有说的很清楚,请谅解。如果你有指教或者疑问,请留言交流!

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值