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这些大厂那里去消 ...
随机推荐
- Android零基础入门第88节:Fragment显示和隐藏、绑定和解绑
在上一期我们学习了FragmentManager和FragmentTransaction的作用,并用案例学习了Fragment的添加.移除和替换,本期一起来学习Fragment显示和隐藏.绑定和解绑. ...
- 改善C#程序的建议6:在线程同步中使用信号量
原文:改善C#程序的建议6:在线程同步中使用信号量 所谓线程同步,就是多个线程之间在某个对象上执行等待(也可理解为锁定该对象),直到该对象被解除锁定.C#中对象的类型分为引用类型和值类型.CLR在这两 ...
- Delphi 7下IGDIPlus库的使用
IGDI+是一个免费开源封装微软GDI+功能的Delphi库,该库使得可以用Delphi语言代码快速简短的实现复杂GDI+应用程序.官方网站:http://www.mitov.com/html/igd ...
- Windows线程生灭(图文并茂)
一.线程创建 Windows线程在创建时会首先创建一个线程内核对象,它是一个较小的数据结构,操作系统通过它来管理线程.新线程可以访问进程内核对象的所有句柄.进程中的所有内存及同一进程中其它线程的栈. ...
- 快速开发第一个SpringBoot应用
通过笔者这段实践SpringBoot的学习,发现自从使用了SpringBoot后,就再也回不去SpringMVC了,因为相比于SpringMVC,SpringBoot真是太高效率了.下面我们看看它效率 ...
- git push 时 failed to push some refs 的解决方案
我们在利用 GIt 上传代码的时候,往往会遇到这样一个问题,导致我们的代码没有办法正常上传到仓库中 造成这个问题的原因其实很简单,就是因为远程仓库和本地库不一致. 基于这样的一个问题,解决办法自然也就 ...
- 《周四橄榄球之夜》流媒体视频拆解:Twitch VS Amazon Prime
文 / Phil Cluff 译 / 王月美 原文链接:https://mux.com/blog/thursday-night-football-streaming-technology-showdo ...
- 从0到1构建网易云信IM私有化
本文来源于MOT技术管理课堂杭州站演讲实录,全文 2410 字,阅读约需 5分钟.网易云信资深研发工程师张翱从私有化面临的问题及需求说起,分享了网易云信IM私有化的解决方案和具体实践. 想要阅读更多技 ...
- 长春理工大学第十四届程序设计竞赛(重现赛)B
B Bowling Game 题目链接:https://ac.nowcoder.com/acm/contest/912/B 题目 CUST的队员打完省赛后,小r带着大家去打保龄球. 保龄球是一项难度非 ...
- [hdu-6395]Sequence 分块+矩阵快速幂
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6395 因为题目数据范围太大,又存在递推关系,用矩阵快速幂来加快递推. 每一项递推时 加的下取整的数随 ...