基于XML的Crystal Report在刷新时不更新子对象 [英] XML-based Crystal Report not updating child objects on refresh

查看:122
本文介绍了基于XML的Crystal Report在刷新时不更新子对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在处理一个需要几种类型的水晶报表的应用程序,标准的命中数据库表,更新连接字符串和刷新报表,完成。另一种类型的Crystal Report是基于一个常规的(稍微复杂的)类对象或POCO对象。

I am working on an application that requires several types of Crystal Reports, "standard" ones that hit a database table, update connection string and refresh the report, done. The other type of Crystal Report is based on a regular (slightly complex) class object, or POCO object.

我面临的问题是报表的数据源是基于我们创建的类,它有属性也是我们创建的类。刷新报表时,对象中的数据会更新,但是子属性对象中的数据不会更新。

The problem I'm facing is that the datasource of the report is based on a class we've created, it has properties that are also classes we've created. When I refresh the report, the data in the object is updated, but the data in the child property objects are not updated. They remain as the values set when I created the report.

有一点背景,环境是使用Crystal Reports 2011的VS2010上的C#。

A bit of background, the environment is C# on VS2010 with Crystal Reports 2011.

为了创建报表,我创建了一个对象,并使用相关数据(包括子对象)填充每个属性,然后将对象导出到XML并将其输出到文件。然后我创建了一个新的报告并添加了一个ADO.NET(XML)类型的数据源。

In order to create the report, I created an object and populated every property with relevant data, including child objects, I then exported the object to XML and outputted it to a file. I then created a new report and added a datasource of the type "ADO.NET (XML)".

所有的表

对于运行时测试,我开始使用StackOverflow问题中的代码:

When it came to runtime testing, I started with the code from this StackOverflow question:

.NET - 将通用集合转换为DataTable

,以将我的对象列表转换为DataTable并将其分配为报表的数据源。如前所述,它适用于第一级,但不适用于子级属性。

in order to convert the list of my objects into a DataTable and assign it as a datasource for the report. As mentioned previously, it works for the first level, but not child properties.

我修改了代码以创建一个新的DataTable,当一个子属性是我们的一个创建类,而不是简单的CLR数据类型,但只是让我一个空报告现在。该代码如下:

I've modified that code to create a new DataTable when a child property is one of our created classes and not simply a CLR data type, but that just leaves me with an empty report now. That code is below:

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;
    }
}

我认为问题是我有一个断开我如何创建报告和数据在更新数据源时如何在运行时应用。

I think the problem is that I've got a disconnect between how I'm creating the report and how the data is being applied at runtime when the datasource is being updated.

但从未做过基于XML的Crystal报表之前,我不知道如何解决这个。我向专家提出的问题有:

But never having done an XML-based Crystal Report before, I'm not exactly sure how to resolve this. My questions to the experts out there are:


  1. 我在正确的轨道上,首先创建报告?

  2. 鉴于我如何创建报告,我在正确的轨道上如何更新报告?

  3. 有更好的方法来达到同样的效果吗?对于作为基于XML的Crystal报表的数据源的多级对象。


推荐答案

解决方案是将对象序列化为MemoryStream,并将其反序列化为一个DataSet,并且Crystal Report能够更新所有表(我到目前为止测试的)。

The solution was to serialize the object to a MemoryStream and to deserialize it back into a DataSet and the Crystal Report was able to update all tables fine (that I've tested so far).

我在我的测试用具应用程序中使用了以下代码,这解决了问题:

I used the following code in my test harness application and this resolved the issue:

        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;

我希望它能帮助别人。

这篇关于基于XML的Crystal Report在刷新时不更新子对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆