动态更改数据库类型,在Crystal Reports源等(为Visual Studio 2012)

问题描述:

我已经研究了如何动态地改变这里的数据源连接在计算器上许多不同的方式。我使用并验证了几乎所有可以找到的c#和vb.net示例,但不知怎的,事情不会按照他们的想法运行。动态更改数据库类型,在Crystal Reports源等(为Visual Studio 2012)

我们项目的想法是将旧报告(即使用xBase dll)的数据源连接更改为crdb_ado.dll和VFPOLEDB提供程序以连接到Visual Foxpro DBF文件(每个文件代表一个表) 。

我已经下载了最新的水晶Developer版本的Visual Studio(2012年)在这里:http://scn.sap.com/docs/DOC-35074 为了能够直接在VS使用这些组件,而引用的DLL在Program Files文件 - 业务对象目录(如中所看到的其他例子)。

我试着通过VS调试器的旧版“更新”报告验证内容(请参阅下面的代码)以及Crystal Reports中新创建的报告(最新版本,它使用正确的路径和设置连接到dbf )所以他们匹配。

不过,我遇到这些问题:

  1. 的代码是能够改变所有参数和属性,但其保存放弃所有更改(文件不是只读)
  2. 更改table.location抛出一个COM异常(翻译:无法加载数据库中的数据,在错误报告)
  3. 当“附接”的报告的文档对象到晶体报告观看者发生同样的情况。
  4. reportDocument.VerifyDatabase()显然失败
  5. 对于据我所看到的,所有的设置都在这两个文件中

的开发环境似乎是windows 7/64/2012 VS临。 Crystal Reports(XI或2011)安装在本机上。我们所有的报告都是使用Crystal Reports的版本9和版本11创建的。

下面是确实更改了所有属性或参数(表格位置除外)的一个修改代码示例。我也使用过使用Propertybag对象的例子,但那些都不起作用。

reportDocument1.Load("path to document"); 

// also tried adding these two lines as a test 
reportDocument1.DataSourceConnections.Clear(); 
reportDocument1.DataSourceConnections[0].SetConnection(@"c:\testreports","",false); 

//changing of table data connections 
foreach (Table table in reportDocument1.Database.Tables) 
{ 
    ChangeTableLogonInfo(table); 
} 

// --- 
private void ChangeTableLogonInfo(Table table) 
{ 
    // server = place containing *.DBF files 
    table.LogOnInfo.ConnectionInfo.ServerName = @"c:\testreports\"; 
    // set to empty string (looking at generated report in CrRep) 
    table.LogOnInfo.ConnectionInfo.DatabaseName = ""; 
    table.LogOnInfo.ConnectionInfo.UserID = ""; 
    table.LogOnInfo.ConnectionInfo.Password = ""; 

    // create logon properties 
    var connectionAttributes = new DbConnectionAttributes(); 
    connectionAttributes.Collection.Set("Collating Sequence","Machine"); 
    connectionAttributes.Collection.Set("Data Source", @"c:\testreports"); 
    connectionAttributes.Collection.Set("Locale Identifier", 1033); 
    connectionAttributes.Collection.Set("OLE DB Services", -5); 
    connectionAttributes.Collection.Set("Provider", "VFPOLEDB"); //eg: SQLOLEDB 
    connectionAttributes.Collection.Set("Use DSN Default Properties",false); 

    // CLEAR and SET NEW attributes for the given table 
    table.LogOnInfo.ConnectionInfo.Attributes.Collection.Clear(); 
    table.LogOnInfo.ConnectionInfo.Attributes.Collection.Add(new NameValuePair2 { Name = "Database DLL", Value = "crdb_ado.dll" }); 
    table.LogOnInfo.ConnectionInfo.Attributes.Collection.Add(new NameValuePair2 { Name = "QE_DatabaseName", Value = "" }); 
    table.LogOnInfo.ConnectionInfo.Attributes.Collection.Add(new NameValuePair2 { Name = "QE_DatabaseType", Value = "OLE DB (ADO)" }); 
    table.LogOnInfo.ConnectionInfo.Attributes.Collection.Add(new NameValuePair2 { Name = "QE_LogonProperties", Value = connectionAttributes }); 
    table.LogOnInfo.ConnectionInfo.Attributes.Collection.Add(new NameValuePair2 { Name = "QE_ServerDescription", Value = @"c:\testreports" }); 
    table.LogOnInfo.ConnectionInfo.Attributes.Collection.Add(new NameValuePair2 { Name = "QE_SQLDB", Value = true }); 
    table.LogOnInfo.ConnectionInfo.Attributes.Collection.Add(new NameValuePair2 { Name = "SSO Enabled", Value = false }); 

    // gives a COM error 
    try 
    { 
     table.Location = "some-table-name";  
    } 
    catch (Exception e) 
    { 
     // handling 
    } 
} 

我们在Crystal Reports中注意到了一些令人讨厌的东西。我想知道它是否与它有关:

当我们想通过CR本身来改变xbase连接时,我们不能从“xbase connection dbf”指向“vfpoledb connection dbf”(如果你理解我的点),而不会丢失报告中的所有字段。

我尝试安装了VS CR开发人员版本的32个和64位版本,但它似乎并没有改变任何东西。

而且,接下来的一段代码不工作在Visual FoxPro中(和我能够在我的水晶阅读这些转换后的文件报告文档查看器)。这只是讨厌它不能轻易完成在C#(它似乎:))

lotest = CREATEOBJECT("crystalruntime.application.9") 
lorap = lotest.openreport("c:\factuur.rpt") 
loData = loRap.Database 
LOCAL lnI 
lnI = 1 
FOR EACH loTable IN lodata.tables 
     loconn = loTable.connectionproperties 
     loTable.dllname = "crdb_odbc.dll" 

     loConn.DeleteAll 
     IF lnI = 1 
      loCOnn.Add("Database", "Hoofding") 
     ELSE 
      loCOnn.Add("Database", "Detail") 
     ENDIF 
     loConn.Add("Database Type","ODBC") 
     loConn.Add("DSN","DBFACTw") 

     lnI = lnI + 1 
ENDFOR 

loRap.Saveas("c:\Factuur2.rpt",2048) 

任何想法或建议?谢谢

我有同样的问题,只有一个星期后,我设法解决它。

ApplyLogOnInfoCrystalDecisions.Shared.Table覆盖ConnectionInfo属性与报告文件中的原始属性并仅更新用户名和密码。

您必须使用PropertyBag而不是DbConnectionAttributesCrystalDecisions.ReportAppServer.DataDefModel.Table而不是CrystalDecisions.Shared.Table

这是我工作的代码:

PropertyBag connectionAttributes = new PropertyBag(); 
connectionAttributes.Add("Auto Translate", "-1"); 
connectionAttributes.Add("Connect Timeout", "15"); 
connectionAttributes.Add("Data Source", Server); 
connectionAttributes.Add("General Timeout", "0"); 
connectionAttributes.Add("Initial Catalog", Database); 
connectionAttributes.Add("Integrated Security", false); 
connectionAttributes.Add("Locale Identifier", "1040"); 
connectionAttributes.Add("OLE DB Services", "-5"); 
connectionAttributes.Add("Provider", "SQLOLEDB"); 
connectionAttributes.Add("Tag with column collation when possible", "0"); 
connectionAttributes.Add("Use DSN Default Properties", false); 
connectionAttributes.Add("Use Encryption for Data", "0"); 

PropertyBag attributes = new PropertyBag(); 
attributes.Add("Database DLL", "crdb_ado.dll"); 
attributes.Add("QE_DatabaseName", Database); 
attributes.Add("QE_DatabaseType", "OLE DB (ADO)"); 
attributes.Add("QE_LogonProperties", connectionAttributes); 
attributes.Add("QE_ServerDescription", Server); 
attributes.Add("QESQLDB", true); 
attributes.Add("SSO Enabled", false); 

CrystalDecisions.ReportAppServer.DataDefModel.ConnectionInfo ci = new CrystalDecisions.ReportAppServer.DataDefModel.ConnectionInfo(); 
ci.Attributes = attributes; 
ci.Kind = CrConnectionInfoKindEnum.crConnectionInfoKindCRQE; 
ci.UserName = Username; 
ci.Password = Password; 

foreach (CrystalDecisions.ReportAppServer.DataDefModel.Table table in Report.ReportClientDocument.DatabaseController.Database.Tables) 
{ 
    CrystalDecisions.ReportAppServer.DataDefModel.Procedure newTable = new CrystalDecisions.ReportAppServer.DataDefModel.Procedure(); 

    newTable.ConnectionInfo = ci; 
    newTable.Name = table.Name; 
    newTable.Alias = table.Alias; 
    newTable.QualifiedName = Database + ".dbo." + table.Name; 
    Report.ReportClientDocument.DatabaseController.SetTableLocation(table, newTable); 
} 

foreach (ReportDocument subreport in Report.Subreports) 
{ 
    foreach (CrystalDecisions.ReportAppServer.DataDefModel.Table table in Report.ReportClientDocument.SubreportController.GetSubreportDatabase(subreport.Name).Tables) 
    { 
     CrystalDecisions.ReportAppServer.DataDefModel.Procedure newTable = new CrystalDecisions.ReportAppServer.DataDefModel.Procedure(); 

     newTable.ConnectionInfo = ci; 
     newTable.Name = table.Name; 
     newTable.Alias = table.Alias; 
     newTable.QualifiedName = Database + ".dbo." + table.Name; 
     Report.ReportClientDocument.SubreportController.SetTableLocation(subreport.Name, table, newTable); 
    } 
} 

我希望这有助于还有其他开发者,因为它是几乎不可能找到SAP文档或支持论坛在这个信息。

+0

我有一个类似的问题,但没有使用ReportAppServer,因为我只是在本地运行报告。我不能为我的生活找出数据库名称的来源 - 它看起来并不像公开显示的那样。使用反射器进行检查时,看起来好像在我的程序集(9.2.3333.0)中似乎将来自ConnectionInfo的信息传递给非托管代码。 this._obfuscatedtablename_(connectionInfo.ServerName,connectionInfo.DatabaseName,connectionInfo.UserID,connectionInfo.Password,true); – agrath 2014-05-23 04:04:44

氖的答案对我来说是一个很大的帮助。除非服务器相同,否则我无法获得大多数人谈论的表循环ApplyLogOnInfo方法。他会用报告文件中的原始值替换所有内容,就像他观察到的那样。

在我的情况下,我只是试图在web.config中使用连接字符串在dev/test/prod数据库之间进行切换。使用DatabaseController.ReplaceConnection是最终为我工作的。我必须克隆(深层复制)现有的ConnectionInfo并对少数相关属性进行更改,而不是尝试从头建立一个或直接修改现有的属性。

public static void SetReportLogOnInfo(ReportDocument report) 
    { 
     if (!report.IsLoaded) 
      report.Refresh(); //workaround for report.FileName empty error 

     foreach (CrystalDecisions.ReportAppServer.DataDefModel.ConnectionInfo oldInfo in report.ReportClientDocument.DatabaseController.GetConnectionInfos()) 
     { 
      var newInfo = oldInfo.Clone(true); 
      newInfo.UserName = [ConnectionString.UserID]; 
      newInfo.Password = [ConnectionString.Password]; 
      newInfo.Attributes["QE_LogonProperties"]["Server"] = [ConnectionString.DataSource]; 
      report.ReportClientDocument.DatabaseController.ReplaceConnection(oldInfo, newInfo, null, CrDBOptionsEnum.crDBOptionDoNotVerifyDB); 
     } 
    }