1

私は、データベーステーブルにアクセスし、接続文字列を更新し、レポートを更新する「標準」のCrystalReportsを必要とするアプリケーションに取り組んでいます。もう1つのタイプのCrystalReportは、通常の(少し複雑な)クラスオブジェクトまたはPOCOオブジェクトに基づいています。

私が直面している問題は、レポートのデータソースが私たちが作成したクラスに基づいており、私たちが作成したクラスでもあるプロパティを持っていることです。レポートを更新すると、オブジェクトのデータは更新されますが、子プロパティオブジェクトのデータは更新されません。これらは、レポートを作成したときに設定された値のままです。

少し背景がありますが、環境はVS2010とCrystal Reports 2011のC#です。

レポートを作成するために、オブジェクトを作成し、子オブジェクトを含む関連データをすべてのプロパティに入力し、オブジェクトをXMLにエクスポートして、ファイルに出力しました。次に、新しいレポートを作成し、「ADO.NET(XML)」タイプのデータソースを追加しました。

すべての「テーブル」は正常に表示され、通常どおりにリンクの作成と追加、レポートのデザインとプレビューを行うことができました。

ランタイムテストに関しては、このStackOverflowの質問のコードから始めました。

.NET-ジェネリックコレクションをDataTableに変換する

オブジェクトのリストをDataTableに変換し、それをレポートのデータソースとして割り当てるため。前述のように、これは最初のレベルでは機能しますが、子プロパティでは機能しません。

子プロパティが作成されたクラスの1つであり、単なるCLRデータ型ではない場合に、新しいDataTableを作成するようにそのコードを変更しましたが、今は空のレポートが残っています。そのコードは以下のとおりです。

public static class CollectionExtensions
{
    /// <summary>Converts to.</summary>
    /// <typeparam name="T">The type value</typeparam>
    /// <param name="list">The list value.</param>
    /// <returns>The data table.</returns>
    public static DataTable ConvertTo<T>(this IList<T> list)
    {
        var entityType = typeof(T);
        var table = CreateTable(entityType);

        foreach (var item in list)
        {
            var row = ConvertToRow(table, item, entityType);
            table.Rows.Add(row);
        }

        return table;
    }

    /// <summary>
    /// Converts to table.
    /// </summary>
    /// <param name="table">The table.</param>
    /// <param name="item">The item value.</param>
    /// <param name="type">The type value.</param>
    /// <returns>returns a data table</returns>
    public static DataRow ConvertToRow(DataTable table, object item, Type type)
    {
        var properties = TypeDescriptor.GetProperties(type);

        var row = table.NewRow();

        foreach (PropertyDescriptor prop in properties)
        {
            if (prop.PropertyType.IsAssignableFrom(typeof(AbstractEntity)))
            {
                var subTable = CreateTable(prop.PropertyType);

                if (prop.GetValue(item) != null)
                {
                    var subRow = ConvertToRow(subTable, prop.GetValue(item), prop.PropertyType);
                    subTable.Rows.Add(subRow);
                }

                row[prop.Name] = subTable;
            }
            else
            {
                row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
            }
        }

        return row;
    }

    /// <summary> Creates the table. </summary>
    /// <param name="type">The type value.</param>
    /// <returns>The datatable</returns>
    public static DataTable CreateTable(Type type)
    {
        var table = new DataTable(type.Name);
        var properties = TypeDescriptor.GetProperties(type);

        foreach (PropertyDescriptor prop in properties)
        {
            if (prop.PropertyType.IsAssignableFrom(typeof(AbstractEntity)))
            {
                table.Columns.Add(prop.Name, typeof(DataTable));
            }
            else
            {
                table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
            }
        }

        return table;
    }
}

問題は、レポートの作成方法と、データソースの更新時に実行時にデータがどのように適用されるかとの間に断絶があることだと思います。

しかし、これまでXMLベースのCrystal Reportを作成したことがないので、これを解決する方法が正確にはわかりません。そこにいる専門家への私の質問は次のとおりです。

  1. そもそもレポートを作成するために、私は正しい方向に進んでいますか?
  2. レポートの作成方法を考えると、レポートの更新方法は正しい方向に進んでいますか?
  3. これと同じ結果を達成するためのより良い方法はありますか?XMLベースのCrystalReportのデータソースであるマルチレベルオブジェクトの場合。
4

1 に答える 1

1

解決策は、オブジェクトをMemoryStreamにシリアル化し、それをデータセットに逆シリアル化することでした。CrystalReportは、すべてのテーブルを正常に更新できました(これまでにテストしました)。

テストハーネスアプリケーションで次のコードを使用しましたが、これで問題が解決しました。

        var xmlDocument = new XmlDocument();
        var serializer = new XmlSerializer(typeof(MyObjectClass));
        using (var stream = new MemoryStream())
        {
            serializer.Serialize(stream, myObjectInstance);
            stream.Flush();
            stream.Seek(0, SeekOrigin.Begin);
            xmlDocument.Load(stream);
        }

        var data = new DataSet();
        var context = new XmlParserContext(null, new XmlNamespaceManager(new NameTable()), null, XmlSpace.None);
        var reader = new XmlTextReader(xmlDocument.OuterXml, XmlNodeType.Document, context);
        data.ReadXml(reader);

        var report = new ReportDocument();
        report.Load(@"C:\Reports\TestReport.rpt", OpenReportMethod.OpenReportByTempCopy);

        report.SetDataSource(data);

        this.crystalReportsViewer.ViewerCore.ReportSource = report;

私はそれがそこにいる他の誰かに役立つことを願っています。

于 2012-11-26T04:14:57.757 に答える