Search code examples
crystal-reportsdependenciescrystal-reports-2008

Crystal Reports - Search Dependencies


Is there a tool that will let you search a number of different crystal reports to see where a specific Table/View/SP is being used?

Scenario is this: We have over 200 reports, so when making a change to a View or Stored Procedure it is not easy to find which reports will be affected without opening each one and checking the "Database expert" or "Datasource location".

I have tried Agent Ransack on them and it doesn't pick any table or view names up.


Solution

  • I never found a tool to do this, so rolled my own in C# .Net 4.0.

    If the crystal report uses a 'SQL Command' instead of dragging in tables, it becomes a bit tricky. I suggest only searching for the TableName rather than the fully qualified Database.dbo.TableName - since this may have been omitted in the pasted SQL Command.

    usage:

    var reports = CrystalExtensions.FindUsages("C:/Reports", "table_name");
    

    code:

    namespace Crystal.Helpers
    {
        using System.Collections.Generic;
        using System.IO;
        using System.Linq;
        using System.Reflection;
        using CrystalDecisions.CrystalReports.Engine;
        using Microsoft.CSharp.RuntimeBinder;
    
        public static class CrystalExtensions
        {
            public static List<string> FindUsages(string directory, string tableName)
            {
                var result = new List<string>();
    
                foreach (var file in Directory.EnumerateFiles(directory, "*.rpt", SearchOption.AllDirectories))
                {
                    using (var report = new ReportClass { FileName = file })
                    {
                        if (report.Database == null) continue;
    
                        var tables = report.Database.Tables.ToList();
                        var hasTable = tables.Any(x => x.Name == tableName || x.GetCommandText().Contains(tableName));
    
                        if (hasTable)
                            result.Add(file);
                    }
                }
    
                return result;
            }
    
            public static List<Table> ToList(this Tables tables)
            {
                var list = new List<Table>();
                var enumerator = tables.GetEnumerator();
    
                while (enumerator.MoveNext())
                    list.Add((Table)enumerator.Current);
    
                return list;
            }
    
            public static string GetCommandText(this Table table)
            {
                var propertyInfo = table.GetType().GetProperty("RasTable", BindingFlags.NonPublic | BindingFlags.Instance);
    
                try
                {
                    return ((dynamic)propertyInfo.GetValue(table, propertyInfo.GetIndexParameters())).CommandText;
                }
                catch (RuntimeBinderException)
                {
                    return ""; // for simplicity of code above, really should return null
                }
            }
        }
    }
    

    Hope that helps!