Excel催化剂开源第50波-Excel与PowerBIDeskTop互通互联之第四篇
答应过的全盘分享,也必承诺到底,此篇PowerBI功能分享的最后一篇,讲述如何导出数据模型的元数据,笔者定义其为模型的数据字典。
此篇对应功能实现出自:第6波-导出PowerbiDesktop模型数据字典https://www.jianshu.com/p/bc26a8dcdfce
关系型数据库有数据字典,分析型数据库更加要有数据字典,DAX建模过程中,若模型的关系复杂,引用的表过多,生成的度量值、计算列过多,单单从PowerBIDeskTop去查看模型关系非常低效。
当然最好的查看方式,在全宇宙里,只能找到Excel了,没有其他敢跟它叫板,所以理所当然地将PowerBIDeskTop模型的元数据,存放到Excel单元格里,结合Excel的排序、筛选、条件格式、单元格格式等友好的操作方式辅助加工查阅模型元数据。
先上代码,同样地此代码也包含了许多Excel的VSTO开发的精髓-使用ListObject对象返回数据。
public static void OutputDataDic(string cnnString, string dbName, string fileName)
{
string shtName = "数据字典_" + fileName;
shtName = shtName.Length > 31 ? shtName.Substring(0, 31) : shtName;
Excel.Worksheet wht;
try
{
wht = Common.ExcelApp.ActiveWorkbook.Worksheets[shtName];
Common.ExcelApp.DisplayAlerts = false;
wht.Delete();
Common.ExcelApp.DisplayAlerts = true;
}
catch (Exception)
{
}
wht = Common.ExcelApp.Worksheets.Add();
wht.Name = shtName;
var vstoSht = Globals.Factory.GetVstoObject(wht);
ListObject listMeasures = vstoSht.Controls.AddListObject(vstoSht.Range["A1"], "度量值表_" + fileName);
ListObject listDims = vstoSht.Controls.AddListObject(vstoSht.Range["C1"], "维度表_" + fileName);
ListObject listRelationShips = vstoSht.Controls.AddListObject(vstoSht.Range["E1"], "关系表_" + fileName);
using (AMO.Server server = new AMO.Server())
{
server.Connect(cnnString);
AMO.Database pbidDb = server.Databases[dbName];
////获取度量值
GetMeasuresTable(pbidDb, listMeasures);
//获取列字段
GetDimsTable(pbidDb, listDims);
////获取关系
GetRelationsTable(pbidDb, listRelationShips);
};
vstoSht.Activate();
}
获取元数据,主要有度量值、维度字段、及表间关系三类元数据。核心代码如下(上方的方法中,最开始是为了访问Sqlserver的SSAS元数据,有区分1200及1100的不同兼容模型版本写了两套代码,因PowerBIDeskTop只会存在1200及以上的兼容模型,故1100的版本已经清除了):
private static DataSet.DataSet1.MeasuresOfLevel1200DataTable GetMeasuresTableOfLevel1200(AMO.Database tabularDb)
{
TOM.Model model = tabularDb.Model;
DataSet.DataSet1.MeasuresOfLevel1200DataTable measuresTable = new DataSet.DataSet1.MeasuresOfLevel1200DataTable();
foreach (TOM.Table table in model.Tables)
{
foreach (TOM.Measure measure in table.Measures)
{
DataSet.DataSet1.MeasuresOfLevel1200Row dr = measuresTable.NewMeasuresOfLevel1200Row();
dr.Measure = $"[{measure.Name}]";
dr.TableName = table.Name;
dr.DisplayFolder = measure.DisplayFolder;
dr.Description = measure.Description;
dr.FormatString = measure.FormatString;
dr.MeasureExpression = measure.Expression;
dr.Visible = !measure.IsHidden;
dr.DataType = measure.DataType.ToString();
measuresTable.AddMeasuresOfLevel1200Row(dr);
}
}
return measuresTable;
}
private static DataTable GetDimsTableOfLevel1200(AMO.Database tabularDb)
{
TOM.Model model = tabularDb.Model;
DataSet.DataSet1.ColumnNamesDataTable dtColumns = new DataSet.DataSet1.ColumnNamesDataTable();
foreach (TOM.Table table in model.Tables)
{
foreach (TOM.Column col in table.Columns)
{
if (!col.Name.Contains("RowNumber"))
{
TOM.CalculatedColumn calCol = col as TOM.CalculatedColumn;
DataSet.DataSet1.ColumnNamesRow dr = dtColumns.NewColumnNamesRow();
dr.TableName = table.Name;
dr.FieldName = col.Name;
dr.FieldType = col.DataType.ToString();
if (calCol != null)
{
dr.DaxExpression = calCol.Expression;
}
dr.Description = col.Description;
dr.Visible = !col.IsHidden;
dtColumns.AddColumnNamesRow(dr);
}
}
}
return dtColumns.Cast<DataSet.DataSet1.ColumnNamesRow>().Where(s => !s.TableName.StartsWith("LocalDateTable"))
.Where(s => !s.TableName.StartsWith("DateTableTemplate"))
.CopyToDataTable<DataSet.DataSet1.ColumnNamesRow>();
}
private static DataTable GetRelationsTableOfLevel1200(AMO.Database tabularDb)
{
TOM.Model model = tabularDb.Model;
DataSet.DataSet1.关系表DataTable dt = new DataSet.DataSet1.关系表DataTable();
foreach (TOM.Relationship relationship in model.Relationships)
{
TOM.SingleColumnRelationship singleRelationShip = relationship as TOM.SingleColumnRelationship;
DataSet.DataSet1.关系表Row dr = dt.New关系表Row();
dr.ToTable = relationship.ToTable.Name;
dr.FromTable = relationship.FromTable.Name;
dr.IsActive = relationship.IsActive;
if (singleRelationShip != null)
{
dr.FromColumn = singleRelationShip.FromColumn.Name;
dr.ToColumn = singleRelationShip.ToColumn.Name;
dr.FromCardinality = singleRelationShip.FromCardinality.ToString();
dr.ToCardinality = singleRelationShip.ToCardinality.ToString();
}
dt.Add关系表Row(dr);
}
return dt.Cast<DataSet.DataSet1.关系表Row>().Where(s => !s.ToTable.StartsWith("LocalDateTable")).CopyToDataTable<DataSet.DataSet1.关系表Row>();
}
结语
连续四篇高质量开源文章,带大家进走Excel催化剂深水区,国际领先的Excel与PowerBIDeskTop互通互联的高级、极高商业价值的核心代码全放送。
最后再次祝愿PowerBI中国社区越来越好,繁荣发展,更多乐于分享的后来者再接再厉。
技术交流QQ群
QQ群名:Excel催化剂开源讨论群, QQ群号:788145319

关于Excel催化剂
Excel催化剂先是一微信公众号的名称,后来顺其名称,正式推出了Excel插件,插件将持续性地更新,更新的周期视本人的时间而定争取一周能够上线一个大功能模块。Excel催化剂插件承诺个人用户永久性免费使用!
Excel催化剂插件使用最新的布署技术,实现一次安装,日后所有更新自动更新完成,无需重复关注更新动态,手动下载安装包重新安装,只需一次安装即可随时保持最新版本!
Excel催化剂插件下载链接:https://pan.baidu.com/s/1Iz2_NZJ8v7C9eqhNjdnP3Q


取名催化剂,因Excel本身的强大,并非所有人能够立马享受到,大部分人还是在被Excel软件所虐的阶段,就是头脑里很清晰想达到的效果,而且高手们也已经实现出来,就是自己怎么弄都弄不出来,或者更糟的是还不知道Excel能够做什么而停留在不断地重复、机械、手工地在做着数据,耗费着无数的青春年华岁月。所以催生了是否可以作为一种媒介,让广大的Excel用户们可以瞬间点燃Excel的爆点,无需苦苦地挣扎地没日没夜的技巧学习、高级复杂函数的烧脑,最终走向了从入门到放弃的道路。
最后Excel功能强大,其实还需树立一个观点,不是所有事情都要交给Excel去完成,也不是所有事情Excel都是十分胜任的,外面的世界仍然是一个广阔的世界,Excel只是其中一枚耀眼的明星,还有其他更多同样精彩强大的技术、工具等。*Excel催化剂也将借力这些其他技术,让Excel能够发挥更强大的爆发!
关于Excel催化剂作者
姓名:李伟坚,从事数据分析工作多年(BI方向),一名同样在路上的学习者。
服务过行业:零售特别是鞋服类的零售行业,电商(淘宝、天猫、京东、唯品会)
技术路线从一名普通用户,通过Excel软件的学习,从此走向数据世界,非科班IT专业人士。
历经重重难关,终于在数据的道路上达到技术平原期,学习众多的知识不再太吃力,同时也形成了自己的一套数据解决方案(数据采集、数据加工清洗、数据多维建模、数据报表展示等)。
擅长技术领域:Excel等Office家族软件、VBA&VSTO的二次开发、Sqlserver数据库技术、Sqlserver的商业智能BI技术、Powerbi技术、云服务器布署技术等等。
2018年开始职业生涯作了重大调整,从原来的正职工作,转为自由职业者,暂无固定收入,暂对前面道路不太明朗,苦重新回到正职工作,对Excel催化剂的运营和开发必定受到很大的影响(正职工作时间内不可能维护也不可能随便把工作时间内的成果公布于外,工作外的时间也十分有限,因已而立之年,家庭责任重大)。
和广大拥护者一同期盼:Excel催化剂一直能运行下去,我所惠及的群体们能够给予支持(多留言鼓励下、转发下朋友圈推荐、小额打赏下和最重点的可以和所在公司及同行推荐推荐,让我的技术可以在贵司发挥价值,实现双赢(初步设想可以数据顾问的方式或一些小型项目开发的方式合作)。
Excel催化剂开源第50波-Excel与PowerBIDeskTop互通互联之第四篇的更多相关文章
- Excel催化剂开源第49波-Excel与PowerBIDeskTop互通互联之第三篇
在PowerBIDeskTop开启的SSAS服务,和Sqlserver所开启的一个本质的区别是,前者其端口号是随机生成的,即上一次打开获得的端口号,下一次关闭后再打开,系统分配给它新的端口号,而后者因 ...
- Excel催化剂开源第51波-Excel催化剂遍历单元格操作性能保障
在Excel催化剂推出的这一年多时间里,经常性听到一种声音,大概意思是真正会写代码的人,都不会看上Excel催化剂写出来的功能,自己造一个更舒服贴心,仿佛会一点VBA就可以天下无敌一般,也好像Exce ...
- Excel催化剂开源第47波-Excel与PowerBIDeskTop互通互联之第一篇
当国外都在追求软件开源,并且在GitHub等平台上产生了大量优质的开源代码时,但在国内却在刮着一股收割小白智商税的知识付费热潮,实在可悲. 互联网的精神乃是分享,让分享带来更多人的受益. 在Power ...
- Excel催化剂开源第48波-Excel与PowerBIDeskTop互通互联之第二篇
前一篇的分享中,主要谈到Excel透视表连接PowerBIDeskTop的技术,在访问SSAS模型时,不止可以使用透视表的方式访问,更可以发数据模型发起DAX或MDX查询,返回一个结果表数据,较透视表 ...
- Excel催化剂开源第40波-Excel插入图片做到极致的效果
不知道是开发人员的自我要求不高还是用户的使用宽容度足够大,在众多Excel插入图片的版本中,都没有考虑到许多的可大幅度提升用户体验的细节处理. Excel催化剂虽然开发水平有限,但也在有限的能力下,尽 ...
- Excel催化剂开源第43波-Excel选择对象Selection在.Net开发中的使用
Excel的二次开发有一极大的优势所在,可以结合用户的交互进行程序的运行,大量用户的交互,都是从选择对象开始,用户选择了单元格区域.图形.图表等对象,之后再进行程序代码的加工处理,生成用户所需的最终结 ...
- Excel催化剂开源第27波-Excel离线生成词云图
在数据分析领域,词云图已经成为在文本分析中装逼的首选图表,大家热烈地讨论如何在Python上做数据分析.做词云图. 数据分析从来都是Excel的主战场,能够让普通用户使用上的技术才是最有价值的技术,一 ...
- Excel催化剂开源第26波-Excel离线生成二维码条形码
在中国特有环境下,二维码.条形码的使用场景非常广泛,因Excel本身就是一个非常不错的报表生成环境,若Excel上能够直接生成二维码.条形码,且是批量化操作的,直接一条龙从数据到报表都由Excel完成 ...
- Excel催化剂开源第25波-Excel调用百度AI,返回AI结果
现成的这些轮子,无需调用网页,直接本地离线即可生成). 当然在AI时代,少不了各种AI接口的使用场景,普通开发者只需聚焦在自己的业务场景上,这些AI底层技术,只需类似水煤电一般去BAT这些大厂那里去消 ...
随机推荐
- UWP开发-获取设备唯一ID
EasClientDeviceInformation deviceInfo = new EasClientDeviceInformation(); this.showDeviceInfo.Items. ...
- win10 uwp 获得Slider拖动结束的值
原文:win10 uwp 获得Slider拖动结束的值 本文讲的是如何获得Slider移动结束的值,也就是触发移动后的值.如果我们监听ValueChanged,在我们鼠标放开之前,只要拖动不放,那么就 ...
- RESTful API设计原则与规范
RESTful API设计原则与规范 一.背景与基础概念 2 二.RESTful API应遵循的原则 3 1.协议(Protocol) 3 2.域名(ROOT URL) 3 3.版本(Versioni ...
- 谷歌推出全新Android开发语言Sky:让App更流畅
土豆网同步更新:http://www.tudou.com/plcover/VHNh6ZopQ4E/ 使用HTML 创建Mac OS App 视频教程. 官方QQ群: (1)App实践出真知 434 ...
- QT Udp组播(穿透)
http://blog.csdn.net/victoryknight/article/details/7814243 主题 UDPQt路由器 局域网内的两台机器如果隔有路由器,那么这两台机器之间不 ...
- Zabbix监控ActiveMQ
当我们在线上使用了ActiveMQ 后,我们需要对一些参数进行监控,比如 消息是否有阻塞,哪个消息队列阻塞了,总的消息数是多少等等.下面我们就通过 Zabbix 结合 Python 脚本来实现对 Ac ...
- 【数据结构】30、hashmap=》hash 计算方式
前提知识 写在前面,为什么num&(length - 1) 在length是2的n次幂的时候等价于num%length n - 1意味着比n最高位小的位都为1,而高的位都为0,因此通过与可以剔 ...
- HTML连载8-video标签
一.video标签 1.作用:播放视频 2.格式:<video src="视频地址“></video> 3.可添加的属性: (1)autoplay="au ...
- Yolov3代码分析与训练自己数据集
现在要针对我们需求引入检测模型,只检测人物,然后是图像能侧立,这样人物在里面占比更多,也更清晰,也不需要检测人占比小的情况,如下是针对这个需求,用的yolov3-tiny模型训练后的效果. Yolov ...
- 【过时】项目转Maven后出现的问题记录
上图,文字后补充 1.过程 创建一个新的web项目,项目名称与原项目名称一致.注意勾选“添加mvn支持(红框部分)”,勾选后运行目标服务器会变为none,这里无法进行添加. 2.项目创建完成后,会报错 ...