1

ここ StackOverflow でデータソース接続を動的に変更する方法について、さまざまな方法を調査しました。見つけたほぼすべての c# と vb.net の例を使用して検証しましたが、どうにかしてうまくいきません。

私たちのプロジェクトのアイデアは、データソース接続を古いレポート (xBase dll を使用している) から VFPOLEDB プロバイダーを使用して crdb_ado.dll に変更し、Visual Foxpro DBF ファイル (各ファイルは 1 つのテーブルを表す) に接続することです。

Visual Studio (2012) の最新の Crystal Developer バージョンをダウンロードしました: http://scn.sap.com/docs/DOC-35074プログラム ファイル で dll を参照せずに、これらのコンポーネントを VS で直接使用できるようにするには-ビジネス オブジェクトディレクトリ (他の例を参照)。

古い「更新された」レポート (以下のコードを参照) の内容を、Crystal Reports で新しく作成されたレポート (正しいパスと設定を使用して dbf に接続する最新バージョン) と一緒に VS デバッガーを介して確認しようとしました。上。

ただし、次の問題が発生しました。

  1. コードはすべてのパラメーターと属性を変更できますが、保存するとすべての変更が破棄されます(ファイルは読み取り専用ではありません) 。
  2. table.location を変更するとcom 例外がスローされます(翻訳: データベース データを読み込めませんでした、レポートにエラーが表示されます)
  3. レポート ドキュメント オブジェクトを Crystal レポート ビューアに「添付」する場合も同様です。
  4. reportDocument.VerifyDatabase() は明らかに失敗します
  5. 私が見る限り、すべての設定は両方のファイルにあるようです

開発環境はWindows 7/64bit/VS 2012 Proです。このマシンには Crystal Reports (XI または 2011) がインストールされています。すべてのレポートは、Crystal Reports のバージョン 9 および 11 で作成されました。

以下は、すべての属性またはパラメーター(テーブルの場所を除く) を変更したコード例の 1 つです。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 接続 dbf" から "vfpoledb 接続 dbf" にポイントすることはできません (私の主張を理解している場合)。

VS CR 開発者版の 32 ビット版と 64 ビット版をインストールしてみましたが、何も変わらないようです。

また、次のコードは Visual FoxPro で機能します (そして、Crystal Reports ドキュメント ビューアでこれらの変換されたファイルを読み取ることができます)。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)

アイデアや提案はありますか?ありがとう

4

2 に答える 2

4

私は同じ問題を抱えていましたが、1週間後にようやく解決しました。

ApplyLogOnInfoof は、属性をレポート ファイルの元の属性でCrystalDecisions.Shared.Table上書きConnectionInfoし、ユーザー名とパスワードのみを更新します。

PropertyBagの代わりにDbConnectionAttributesとのCrystalDecisions.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 ドキュメントやサポート フォーラムでこの情報を見つけることはほぼ不可能なので、これが他の開発者にも役立つことを願っています。

于 2013-06-19T10:58:15.193 に答える
3

ネオンの答えは私にとって大きな助けになりました。サーバーが同じでない限り、ほとんどの人が話しているテーブル ループ 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);
        }
    }
于 2013-07-22T21:13:03.390 に答える