2009-06-12 Bill Holmes <billholmes54@gmail.com>
[mono.git] / mcs / class / System.Data.Linq / src / DbLinq / Vendor / Implementation / SchemaLoader.ForeignKey.cs
1 #region MIT license\r
2 // \r
3 // MIT license\r
4 //\r
5 // Copyright (c) 2007-2008 Jiri Moudry, Pascal Craponne\r
6 // \r
7 // Permission is hereby granted, free of charge, to any person obtaining a copy\r
8 // of this software and associated documentation files (the "Software"), to deal\r
9 // in the Software without restriction, including without limitation the rights\r
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
11 // copies of the Software, and to permit persons to whom the Software is\r
12 // furnished to do so, subject to the following conditions:\r
13 // \r
14 // The above copyright notice and this permission notice shall be included in\r
15 // all copies or substantial portions of the Software.\r
16 // \r
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
23 // THE SOFTWARE.\r
24 // \r
25 #endregion\r
26 \r
27 using System.Data;\r
28 using System.Linq;\r
29 using DbLinq.Schema;\r
30 using DbLinq.Schema.Dbml;\r
31 \r
32 namespace DbLinq.Vendor.Implementation\r
33 {\r
34     partial class SchemaLoader\r
35     {\r
36         /// <summary>\r
37         /// Loads the constraints.\r
38         /// </summary>\r
39         /// <param name="schema">The schema.</param>\r
40         /// <param name="schemaName">Name of the schema.</param>\r
41         /// <param name="conn">The conn.</param>\r
42         /// <param name="nameFormat">The name format.</param>\r
43         /// <param name="names">The names.</param>\r
44         protected abstract void LoadConstraints(Database schema, SchemaName schemaName, IDbConnection conn, NameFormat nameFormat, Names names);\r
45 \r
46         /// <summary>\r
47         /// Loads the foreign key.\r
48         /// </summary>\r
49         /// <param name="schema">The schema.</param>\r
50         /// <param name="table">The table.</param>\r
51         /// <param name="columnName">Name of the column.</param>\r
52         /// <param name="tableName">Name of the table.</param>\r
53         /// <param name="tableSchema">The table schema.</param>\r
54         /// <param name="referencedColumnName">Name of the referenced column.</param>\r
55         /// <param name="referencedTableName">Name of the referenced table.</param>\r
56         /// <param name="referencedTableSchema">The referenced table schema.</param>\r
57         /// <param name="constraintName">Name of the constraint.</param>\r
58         /// <param name="nameFormat">The name format.</param>\r
59         /// <param name="names">The names.</param>\r
60         protected virtual void LoadForeignKey(Database schema, Table table, string columnName, string tableName, string tableSchema,\r
61             string referencedColumnName, string referencedTableName, string referencedTableSchema,\r
62             string constraintName,\r
63             NameFormat nameFormat, Names names)\r
64         {\r
65             var foreignKey = names.ColumnsNames[tableName][columnName].PropertyName;\r
66             var reverseForeignKey = names.ColumnsNames[referencedTableName][referencedColumnName].PropertyName;\r
67 \r
68             var associationName = CreateAssociationName(tableName, tableSchema,\r
69                 referencedTableName, referencedTableSchema, constraintName, foreignKey, nameFormat);\r
70 \r
71             //both parent and child table get an [Association]\r
72             var assoc = new Association();\r
73             assoc.IsForeignKey = true;\r
74             assoc.Name = constraintName;\r
75             assoc.Type = null;\r
76             assoc.ThisKey = foreignKey;\r
77             assoc.OtherKey = reverseForeignKey;\r
78             assoc.Member = associationName.ManyToOneMemberName;\r
79             assoc.Cardinality = Cardinality.Many; // TODO: check this is the right direction (even if it appears to be useless)\r
80             table.Type.Associations.Add(assoc);\r
81 \r
82             //and insert the reverse association:\r
83             var reverseAssociation = new Association();\r
84             reverseAssociation.Name = constraintName;\r
85             reverseAssociation.Type = table.Type.Name;\r
86             reverseAssociation.Member = associationName.OneToManyMemberName;\r
87             reverseAssociation.Cardinality = Cardinality.One;\r
88             reverseAssociation.ThisKey = reverseForeignKey;\r
89             reverseAssociation.OtherKey = foreignKey;\r
90             reverseAssociation.DeleteRule = "NO ACTION";\r
91 \r
92             string referencedFullDbName = GetFullDbName(referencedTableName, referencedTableSchema);\r
93             var referencedTable = schema.Tables.FirstOrDefault(t => referencedFullDbName == t.Name);\r
94             if (referencedTable == null)\r
95             {\r
96                 //try case-insensitive match \r
97                 //reason: MySql's Key_Column_Usage table contains both 'Northwind' and 'northwind'\r
98                 referencedTable = schema.Tables.FirstOrDefault(t => referencedFullDbName.ToLower() == t.Name.ToLower());\r
99             }\r
100 \r
101             if (referencedTable == null)\r
102             {\r
103                 ReportForeignKeyError(schema, referencedFullDbName);\r
104             }\r
105             else\r
106             {\r
107                 referencedTable.Type.Associations.Add(reverseAssociation);\r
108                 assoc.Type = referencedTable.Type.Name;\r
109             }\r
110         }\r
111 \r
112         /// <summary>\r
113         /// Reports a foreign key error.\r
114         /// </summary>\r
115         /// <param name="schema">The schema.</param>\r
116         /// <param name="referencedTableFull">The referenced table full.</param>\r
117         private void ReportForeignKeyError(Database schema, string referencedTableFull)\r
118         {\r
119             var tablesMap = schema.Tables.ToDictionary(t => t.Name.ToLower());\r
120             var referencedTableFullL = referencedTableFull.ToLower();\r
121 \r
122             string msg = "ERROR L91: parent table not found: " + referencedTableFull;\r
123             Table matchedTable;\r
124             if (tablesMap.TryGetValue(referencedTableFullL, out matchedTable))\r
125             {\r
126                 //case problems arise from various reasons,\r
127                 //e.g. different capitalization on WIndows vs Linux,\r
128                 //bugs in DbLinq etc\r
129                 msg += " - however, schema lists a table spelled as " + matchedTable.Name;\r
130             }\r
131             WriteErrorLine(msg);\r
132         }\r
133     }\r
134 }\r