水晶报表使用,解决相同数据库不同服务器使用同一个水晶报表模板问题?
在使用asp.net时,做ERP系统时,水晶报表是经常被使用的,在asp.net 上有水晶报表的控件,那个网上有很多,这里就不多讲了,水晶报表有两种模式即push模式和pull模式,pull模式是:使用设计报表时的链接数据库驱动获取打印表格,这个不需要写sql语句,代码量非常少,push模式即自己构造需要sql语句,代码量大,扩展报表的功能。
在一次项目中,我遇到需要使用水晶报表的api,这里水晶报表主要使用的api是:
using CrystalDecisions.CrystalReports.Engine;
using CrystalDecisions.ReportSource;
using CrystalDecisions.Shared;
有经验的知道打印报表需要使用Engine.ReportDocument.setdatabaseLogon(string,string,string,string);这只是其中的一个重载。这就是配置pull模式,设计连接的数据库。但是在下遇到了一个需求是:有个水晶报表模板,比如说是在A数据库上设计的,但是B服务器有一个和A服务器一样的数据库结构,为了以后维护客户资料方便,必须实现更改配置实现,水晶模板在两个A、B之间的切换,但是水晶报表模板不变。
分析:这个需求显然是你不能使用sql语句进行push模式的操作。但是使用上面给出的api配置发现,直接报错:database log error;这个是我很是纠结,但是这个功能必须要实现,我也在网上找了很多资料,没有合理的解决。
我的分析(不对的地方请指正),我想这个配置服务器的函数内部是怎么实现的呢,我在网上找了一个C# 反编译工具,进行查看,看看Sap公司在里面封装了何方神圣。我把图片贴出来方便大家理解:首先找到这个api函数,也就是CrystalDecisions.CrystalReports.Engine-》ReportDocument-》setdatabaseLogon。
可以看到里面有个调用自身。继续往下面走,就发现:
调用了一个表格登录,这是什么东西,莫着急,继续点击往下看。
到这里你应该明白了,原来这个登录数据库设置是在pull模式下,调用了默认的数据库服务器名和数据库,这也就明白了为什么在函数setdatabaselogon();上更改服务器名,虽然数据库一样,提示登录数据库失败的原因。
说了这么多,问题的根源终于找到了,但是怎么解决呢,这才是重点,从第三个图中可以看出它是 把信息应用到没哟个数据中,既然这样我们可以模仿他的方法进行重写自己的链接数据。
1 #region 转换服务器连接 2 ConnectionInfo connectinfo = new ConnectionInfo() 3 { 4 ServerName = sqlhelper.CrystalStrServer, 5 DatabaseName = sqlhelper.CrystalDatabase, 6 UserID = sqlhelper.CrystalStrUser, 7 Password = sqlhelper.CrystalStrPwd 8 }; 9 foreach (CrystalDecisions.CrystalReports.Engine.Table tb1 in rd.Database.Tables) 10 { 11 tb1.LogOnInfo.ConnectionInfo = connectinfo; 12 tb1.ApplyLogOnInfo(tb1.LogOnInfo); 13 }
这个代码使用可以解决你的问题,但是它会出现一点小BUG。什么bug呢,当你使用更改配置后假设使用A,使用默认水晶报表下载,下载的数据仍然是B的数据。怎么办呢,不要着急,在加一行代码就可以搞定了。
CrystalDecisions.CrystalReports.Engine.ReportDocument rd = new ReportDocument(); string rpt1 = Context.Server.MapPath("/CrystalReportsPath/" + StrGuid.Trim() + reportPath); rd.Load(rpt1); #region 转换服务器连接 ConnectionInfo connectinfo = new ConnectionInfo() { ServerName = sqlhelper.CrystalStrServer, DatabaseName = sqlhelper.CrystalDatabase, UserID = sqlhelper.CrystalStrUser, Password = sqlhelper.CrystalStrPwd }; foreach (CrystalDecisions.CrystalReports.Engine.Table tb1 in rd.Database.Tables) { tb1.LogOnInfo.ConnectionInfo = connectinfo; tb1.ApplyLogOnInfo(tb1.LogOnInfo); } //一定要刷新 rd.Refresh(); #endregion
到这里问题就解决了。