5 // Copyright (c) 2007-2008 Jiri Moudry, Pascal Craponne
\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
14 // The above copyright notice and this permission notice shall be included in
\r
15 // all copies or substantial portions of the Software.
\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
29 using DbLinq.Schema;
\r
30 using DbLinq.Schema.Dbml;
\r
32 namespace DbLinq.Vendor.Implementation
\r
34 partial class SchemaLoader
\r
37 /// Loads the constraints.
\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
47 /// Loads the foreign key.
\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
65 var foreignKey = names.ColumnsNames[tableName][columnName].PropertyName;
\r
66 var reverseForeignKey = names.ColumnsNames[referencedTableName][referencedColumnName].PropertyName;
\r
68 var associationName = CreateAssociationName(tableName, tableSchema,
\r
69 referencedTableName, referencedTableSchema, constraintName, foreignKey, nameFormat);
\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
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
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
92 string referencedFullDbName = GetFullDbName(referencedTableName, referencedTableSchema);
\r
93 var referencedTable = schema.Tables.FirstOrDefault(t => referencedFullDbName == t.Name);
\r
94 if (referencedTable == null)
\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
101 if (referencedTable == null)
\r
103 ReportForeignKeyError(schema, referencedFullDbName);
\r
107 referencedTable.Type.Associations.Add(reverseAssociation);
\r
108 assoc.Type = referencedTable.Type.Name;
\r
113 /// Reports a foreign key error.
\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
119 var tablesMap = schema.Tables.ToDictionary(t => t.Name.ToLower());
\r
120 var referencedTableFullL = referencedTableFull.ToLower();
\r
122 string msg = "ERROR L91: parent table not found: " + referencedTableFull;
\r
123 Table matchedTable;
\r
124 if (tablesMap.TryGetValue(referencedTableFullL, out matchedTable))
\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
131 WriteErrorLine(msg);
\r