c62137e02447c06c970b563fc6fcfb78f4fa4d28
FAQ/many-to-many-database-join.md
| ... | ... | @@ -12,7 +12,26 @@ In order to achieve the results required for this scenario, some understanding a |
| 12 | 12 | |
| 13 | 13 | For this tutorial, all changes being made will exist in your CustomAdHocConfig class that is normally contained inside the Global.asax. |
| 14 | 14 | |
| 15 | -First, we need to modify the [[InitializeReporting()|/FAQ/InitializeReporting]] method: |
|
| 15 | +First, we need an instance variable to hold a reference to the driver. |
|
| 16 | + |
|
| 17 | +``` csharp |
|
| 18 | +Public Class CustomAdHocConfig : FileSystemAdHocConfig |
|
| 19 | + private oldDriver As Driver = null; |
|
| 20 | + |
|
| 21 | + {...} 'InitializeReporting, PreExecuteReportSet, etc. |
|
| 22 | +End Class |
|
| 23 | +``` |
|
| 24 | + |
|
| 25 | +``` visualbasic |
|
| 26 | +public class CustomAdHocConfig Inherits FileSystemAdHocConfig |
|
| 27 | +{ |
|
| 28 | + private oldDriver As Drier = Nothing |
|
| 29 | + |
|
| 30 | + {...} //InitializeReporting, PreExecuteReportSet, etc. |
|
| 31 | +} |
|
| 32 | +``` |
|
| 33 | + |
|
| 34 | +Next, we need to modify the [[InitializeReporting()|/FAQ/InitializeReporting]] method: |
|
| 16 | 35 | |
| 17 | 36 | ``` csharp |
| 18 | 37 | public static void InitializeReporting() { |
| ... | ... | @@ -24,6 +43,7 @@ public static void InitializeReporting() { |
| 24 | 43 | AdHocSettings.SqlServerConnectionString = @"INSERT_YOUR_CONNECTION_STRING_HERE"; |
| 25 | 44 | {...} |
| 26 | 45 | AdHocContext.Driver.AddConstraint("[dbo].[Orders].[ShipName]", "[dbo].[Suppliers].[CompanyName]"); |
| 46 | + AdHocSettings.visibleDataSources = new string[] { "[dbo].[Orders]", "[dbo].[Suppliers]" }; //Set our visible data sources to exclude our middle table |
|
| 27 | 47 | HttpContext.Current.Session["ReportingInitialized"] = true; |
| 28 | 48 | } |
| 29 | 49 | ``` |
| ... | ... | @@ -42,7 +62,7 @@ Public Shared Sub InitializeReporting() |
| 42 | 62 | HttpContext.Current.Session("ReportingInitialized") = True |
| 43 | 63 | End Sub |
| 44 | 64 | ``` |
| 45 | -The statement critical to the [[InitializeReporting()|/FAQ/InitializeReporting]] method is the AddConstraint method call. Here, we set up a relationship between two columns in our two tables with a many-to-many relationship. At this point, the connector table has not entered the equation. This constraint must exist in order to select the two tables with a many-to-many relationship on the datasources tab. |
|
| 65 | +The statement critical to the [[InitializeReporting()|/FAQ/InitializeReporting]] method is the AddConstraint method call. Here, we set up a relationship between two columns in our two tables with a many-to-many relationship. At this point, the connector table has not entered the equation. This constraint must exist in order to select the two tables with a many-to-many relationship on the datasources tab. We will also reset the driver to re-obtain the database schema objects. This is because setting VisibleDataSources after the initialization of the current driver will not load the columns for any additional data sources. |
|
| 46 | 66 | |
| 47 | 67 | _*NOTE:* The two columns in the fake constraint MUST have the same datatype._ |
| 48 | 68 | |
| ... | ... | @@ -51,7 +71,11 @@ Next, we modify the [[PreExecuteReportSet()|/FAQ/PreExecuteReportSet]] method. |
| 51 | 71 | ``` csharp |
| 52 | 72 | public override void PreExecuteReportSet(ReportSet reportSet) { |
| 53 | 73 | base.PreExecuteReportSet(reportSet); |
| 54 | - AdHocContext.Driver.RemoveConstraint("[dbo].[Orders].[ShipName]", "[dbo].[Suppliers].[CompanyName]"); //temporarily remove the constraint |
|
| 74 | + oldDriver = AdHocContext.Driver; |
|
| 75 | + AdHocContext.Driver = new MSSQLDriver(AdHocSettings.SqlServerConnectionString); //Set the specific type of driver we were using before |
|
| 76 | + AdHocSettings.VisibleDataSources = new string[] { "[dbo].[Orders]", [dbo].[Suppliers]", "[dbo].[testcon]" }; //testcon is the name of the middle table we want to join with |
|
| 77 | + AdHocContext.Driver.AddConstraint("[dbo].[Orders].[OrderID]", "[dbo].[testcon].[ordernum]"); |
|
| 78 | + AdHocContext.Driver.AddConstraint("[dbo].[Suppliers].[SupplierID]", "[dbo].[testcon].[supplier]"); //Add the correct constraints to the driver |
|
| 55 | 79 | if(reportSet.JoinedTables.Count > 0) //check if we have selected multiple tables |
| 56 | 80 | { |
| 57 | 81 | IEnumerable<JoinedTable> jts = (from JoinedTable jt in reportSet.JoinedTables |
| ... | ... | @@ -59,7 +83,7 @@ public override void PreExecuteReportSet(ReportSet reportSet) { |
| 59 | 83 | (jt.RightConditionTable.Contains("Orders") || jt.RightConditionTable.Contains("Suppliers")) |
| 60 | 84 | select jt); //use LINQ to check if we selected the tables we want to define the relationship for |
| 61 | 85 | JoinedTable middleJT = new JoinedTable(){ |
| 62 | - TableName = "[dbo].[testcon]" //This is our connector table |
|
| 86 | + TableName = "[dbo].[testcon]" |
|
| 63 | 87 | }; |
| 64 | 88 | if(jts.Count() == 2) //We have both tables that we want |
| 65 | 89 | { |
| ... | ... | @@ -67,7 +91,7 @@ public override void PreExecuteReportSet(ReportSet reportSet) { |
| 67 | 91 | reportSet.JoinedTables.Remove(jts.ToArray()[1]); |
| 68 | 92 | reportSet.JoinedTables.Remove(jts.ToArray()[0]); |
| 69 | 93 | //if any other joined tables exist, you can modify them according to your needs. This tutorial will not cover that scenario. |
| 70 | - reportSet.JoinedTables.Add(middleJT); //Add the connector table |
|
| 94 | + reportSet.JoinedTables.Add(middleJT); //Add the connector table first. In this example, it will be the table in the FROM. Orders and Suppliers will be the JOINed tables. |
|
| 71 | 95 | reportSet.JoinedTables.Add(new JoinedTable() |
| 72 | 96 | { |
| 73 | 97 | TableName = "[dbo].[Orders]", |
| ... | ... | @@ -93,7 +117,11 @@ public override void PreExecuteReportSet(ReportSet reportSet) { |
| 93 | 117 | ``` visualbasic |
| 94 | 118 | Public Overrides Sub PreExecuteReportSet(ByVal reportSet As ReportSet) |
| 95 | 119 | MyBase.PreExecuteReportSet(reportSet) |
| 96 | - AdHocContext.Driver.RemoveConstraint("[dbo].[Orders].[ShipName]", "[dbo].[Suppliers].[CompanyName]") |
|
| 120 | + oldDriver = AdHocContext.Driver |
|
| 121 | + AdHocContext.Driver = new MSSQLDriver(AdHocSettings.SqlServerConnectionString) 'Set the specific type of driver we were using before |
|
| 122 | + AdHocSettings.VisibleDataSources = New string() { "[dbo].[Orders]", [dbo].[Suppliers]", "[dbo].[testcon]" } 'testcon is the name of the middle table we want to join with |
|
| 123 | + AdHocContext.Driver.AddConstraint("[dbo].[Orders].[OrderID]", "[dbo].[testcon].[ordernum]") |
|
| 124 | + AdHocContext.Driver.AddConstraint("[dbo].[Suppliers].[SupplierID]", "[dbo].[testcon].[supplier]") 'Add the correct constraints to the driver |
|
| 97 | 125 | If (reportSet.JoinedTables.Count > 0) Then |
| 98 | 126 | Dim jts As IEnumerable(Of JoinedTable) = (From jt As JoinedTable In reportSet.JoinedTables |
| 99 | 127 | Where (jt.DbTable.Name.Contains("Orders") OrElse jt.DbTable.Name.Contains("Suppliers")) OrElse |
| ... | ... | @@ -128,22 +156,22 @@ End Sub |
| 128 | 156 | |
| 129 | 157 | The above code in the [[PreExecuteReportSet()|/FAQ/PreExecuteReportSet]] method will re-define the relationship between the two tables in a many-to-many relationship and insert the connector table silently. This will produce a working join on the two tables while leaving out the pre-defined fake join. The user will be able to freely select the two tables in the many-to-many relationship without seeing the connecting table. |
| 130 | 158 | |
| 131 | -Finally, we need a statement in the [[PostExecuteReportSet()|/FAQ/PostExecuteReportSet]] method. |
|
| 159 | +Finally, we need a statement in the [[PostExecuteReportSet()|/FAQ/PostExecuteReportSet]] method to reset the driver. |
|
| 132 | 160 | |
| 133 | 161 | ``` csharp |
| 134 | 162 | public override void PostExecuteReportSet(ReportSet reportSet) |
| 135 | 163 | { |
| 136 | 164 | base.PostExecuteReportSet(reportSet); |
| 137 | - AdHocContext.Driver.AddConstraint("[dbo].[Orders].[ShipName]", "[dbo].[Suppliers].[CompanyName]"); |
|
| 165 | + AdHocContext.Driver = oldDriver; |
|
| 138 | 166 | } |
| 139 | 167 | ``` |
| 140 | 168 | |
| 141 | 169 | ``` visualbasic |
| 142 | 170 | Public Overrides Sub PostExecuteReportSet(ByVal reportSet As ReportSet) |
| 143 | 171 | MyBase.PostExecuteReportSet(reportSet) |
| 144 | - AdHocContext.Driver.AddConstraint("[dbo].[Orders].[ShipName]", "[dbo].[Suppliers].[CompanyName]") |
|
| 172 | + AdHocContext.Driver = oldDriver |
|
| 145 | 173 | End Sub |
| 146 | 174 | ``` |
| 147 | 175 | |
| 148 | 176 | |
| 149 | -Re-adding the constraint after report execution will ensure that the tables will be selectable again when the user makes subsequent trips to the Report Designer. Other users in the system without the ability to select the datasources in question will not see any change in their current behavior. Report definitions using the relationship will not reflect the internal process. The fake constraint will appear in the definition. |
|
| ... | ... | \ No newline at end of file |
| 0 | +Resetting the driver after report execution will ensure that the tables with no relationship will be selectable again when the user makes subsequent trips to the Report Designer. Other users in the system without the ability to select the datasources in question will not see any change in their current behavior. Report definitions using the relationship will not reflect the internal process. The fake constraint will appear in the definition. |
|
| ... | ... | \ No newline at end of file |