XML-based Crystal Report does not update child objects when updating

I am working on an application that requires several types of Crystal Reports, the β€œstandard” ones that fall into the database table, update the connection string and update the report. Another type of Crystal Report is based on a regular (slightly complex) class object or POCO object.

The problem I am facing is that the report data source is based on the class we created, it has properties that are also the classes we created. When I update the report, the data in the object is updated, but the data in the objects of the child object is not updated. They remain as the values ​​set when creating the report.

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

To create a report, I created an object and populated each property with relevant data, including child objects, then I exported the object to XML and output it to a file. Then I created a new report and added a data source like "ADO.NET (XML)".

All the β€œtables” turned out to be beautiful, and I was able to create and add links, design and view the report, as usual.

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

.NET - Convert a shared collection to a DataTable

to convert the list of my objects to a DataTable and assign it as the data source for the report. As mentioned earlier, it works for the first level, but not for child properties.

I modified this code to create a new DataTable when the child property is one of our created classes, and not just a CLR data type, but now this leaves me with an empty report. This 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 have a gap between how I create the report and how the data is applied at runtime when the data source is updated.

But I've never done an XML-based Crystal Report before, I'm not quite sure how to solve this. My questions to experts:

  • Am I on the right track to create a report in the first place?
  • Given how I create the report, can I choose the right way how I update the report?
  • Is there a better way to achieve the same result? For the tiered object that is the data source for the Crystal Report XML report.
+1
source share
1 answer

The solution was to serialize the object into a MemoryStream and deserialize it back to the DataSet, and Crystal Report was able to completely update all the tables (which I have tested so far).

I used the following code in the application for testing, and this solved the problem:

  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; 

I hope this helps someone else.

+1
source

All Articles