1212<#@ import namespace="System.Data.Entity.Infrastructure.Pluralization" #>
1313<#@ import namespace="System.Text.RegularExpressions" #>
1414<#@ import namespace="System.Configuration" #>
15+ <#@ import namespace="System.Runtime.CompilerServices" #>
1516<#@ import namespace="EnvDTE" #>
1617<#@ output extension=".cs"#>
1718<#
782783 // Calculates the relationship between a child table and it's parent table.
783784 public static Relationship CalcRelationshipSingle(Table parentTable, Table childTable, Column childTableCol, Column parentTableCol)
784785 {
785- bool childTableSinglePrimaryKey = (childTable.PrimaryKeys.Count() == 1);
786- bool parentTableSinglePrimaryKey = (parentTable.PrimaryKeys.Count() == 1) ;
786+ if(!childTableCol.IsPrimaryKey && !childTableCol.IsUniqueConstraint)
787+ return Relationship.ManyToOne ;
787788
788- // 1:1
789- if(childTableCol.IsPrimaryKey && parentTableCol.IsPrimaryKey && childTableSinglePrimaryKey && parentTableSinglePrimaryKey)
790- return Relationship.OneToOne;
789+ if(!parentTableCol.IsPrimaryKey && !parentTableCol.IsUniqueConstraint)
790+ return Relationship.ManyToOne;
791791
792- return Relationship.ManyToOne;
792+ if (childTable.PrimaryKeys.Count() != 1)
793+ return Relationship.ManyToOne;
794+
795+ if (parentTable.PrimaryKeys.Count() != 1)
796+ return Relationship.ManyToOne;
797+
798+ return Relationship.OneToOne;
793799 }
794800
795801 public class EnumDefinition
832838 public bool IsIdentity;
833839 public bool IsNullable;
834840 public bool IsPrimaryKey;
835- public bool IsPrimaryKeyViaUniqueIndex;
841+ public bool IsUniqueConstraint;
842+ public bool IsUnique;
836843 public bool IsStoreGenerated;
837844 public bool IsRowVersion;
838845 public bool IsConcurrencyToken; // Manually set via callback
866873 comments = Name;
867874 if (IsPrimaryKey)
868875 {
869- if (IsPrimaryKeyViaUniqueIndex )
876+ if (IsUniqueConstraint )
870877 comments += " (Primary key via unique index " + UniqueIndexName + ")";
871878 else
872879 comments += " (Primary key)";
@@ -2591,29 +2598,32 @@ SELECT SERVERPROPERTY('Edition') AS Edition,
25912598 var indexes =
25922599 list.Where(x => x.Schema == indexTable.Schema && x.TableName == indexTable.TableName)
25932600 .OrderBy(o => o.ColumnCount)
2594- .ThenBy(o => o.KeyOrdinal);
2601+ .ThenBy(o => o.KeyOrdinal)
2602+ .ToList();
25952603
25962604 // Set index on column
25972605 foreach (var index in indexes)
25982606 {
25992607 var col = t.Columns.Find(x => x.Name == index.ColumnName);
2600- if (col != null)
2601- {
2602- col.Indexes.Add(index);
2603- if (!col.IsPrimaryKey && index.IsPrimaryKey)
2604- col.IsPrimaryKey = true;
2605- }
2608+ if (col == null)
2609+ continue;
2610+
2611+ col.Indexes.Add(index);
2612+
2613+ col.IsPrimaryKey = col.IsPrimaryKey || index.IsPrimaryKey;
2614+ col.IsUniqueConstraint = col.IsUniqueConstraint || (index.IsUniqueConstraint && index.ColumnCount == 1);
2615+ col.IsUnique = col.IsUnique || (index.IsUnique && index.ColumnCount == 1);
26062616 }
26072617
26082618 // Check if table has any primary keys
26092619 if (t.PrimaryKeys.Any())
26102620 continue; // Already has a primary key, ignore this unique index / constraint
26112621
26122622 // Find unique indexes for table
2613- var uniqueIndexKeys =
2614- indexes .Where(x => x.IsUnique || x.IsPrimaryKey || x.IsUniqueConstraint)
2615- .OrderBy(o => o.ColumnCount)
2616- .ThenBy(o => o.KeyOrdinal);
2623+ var uniqueIndexKeys = indexes
2624+ .Where(x => x.IsUnique || x.IsPrimaryKey || x.IsUniqueConstraint)
2625+ .OrderBy(o => o.ColumnCount)
2626+ .ThenBy(o => o.KeyOrdinal);
26172627
26182628 // Process only the first index with the lowest unique column count
26192629 string indexName = null;
@@ -2629,7 +2639,8 @@ SELECT SERVERPROPERTY('Edition') AS Edition,
26292639 if (col != null && !col.IsNullable && !col.Hidden && !col.IsPrimaryKey)
26302640 {
26312641 col.IsPrimaryKey = true;
2632- col.IsPrimaryKeyViaUniqueIndex = true;
2642+ col.IsUniqueConstraint = true;
2643+ col.IsUnique = true;
26332644 col.UniqueIndexName = indexName;
26342645 }
26352646 }
@@ -2878,31 +2889,50 @@ SELECT SERVERPROPERTY('Edition') AS Edition,
28782889
28792890 var fkCols = foreignKeys.Select(x => new
28802891 {
2881- fkOrdinal = x.Ordinal ,
2892+ fk = x,
28822893 col = fkTable.Columns.Find(n => string.Equals(n.Name, x.FkColumn, StringComparison.InvariantCultureIgnoreCase))
28832894 })
28842895 .Where(x => x.col != null)
2885- .OrderBy(o => o.fkOrdinal )
2896+ .OrderBy(o => o.fk.Ordinal )
28862897 .ToList();
28872898
28882899 if (!fkCols.Any())
28892900 continue;
28902901
2902+ //if(EF6)
2903+ {
2904+ // Check FK has same number of columns as the primary key it points to
2905+ var pks = pkTable.PrimaryKeys.OrderBy(x => x.PropertyType).ThenBy(y => y.Name).ToArray();
2906+ var cols = fkCols.Select(x => x.col).OrderBy(x => x.PropertyType).ThenBy(y => y.Name).ToArray();
2907+ if (pks.Length != cols.Length)
2908+ continue;
2909+
2910+ // EF6 - Cannot have a FK to a non-primary key
2911+ if(pks.Where((pk, ef6Check) => pk.PropertyType != cols[ef6Check].PropertyType).Any())
2912+ continue;
2913+ }
2914+
28912915 var pkCols = foreignKeys.Select(x => pkTable.Columns.Find(n => string.Equals(n.Name, x.PkColumn, StringComparison.InvariantCultureIgnoreCase)))
2892- .Where(x => x != null && x.IsPrimaryKey )
2916+ .Where(x => x != null)
28932917 .OrderBy(o => o.Ordinal)
28942918 .ToList();
28952919
28962920 if (!pkCols.Any())
28972921 continue;
28982922
2899- var fkCol = fkCols.First();
2900- var pkCol = pkCols.First();
2901-
29022923 var relationship = CalcRelationship(pkTable, fkTable, fkCols.Select(c => c.col).ToList(), pkCols);
29032924 if (relationship == Relationship.DoNotUse)
29042925 continue;
29052926
2927+ if(fkCols.All(x => !x.col.IsNullable && !x.col.Hidden) && pkCols.All(x => x.IsPrimaryKey || x.IsUnique))
2928+ {
2929+ foreach (var fk in fkCols)
2930+ fk.fk.IncludeRequiredAttribute = true;
2931+ }
2932+
2933+ var fkCol = fkCols.First();
2934+ var pkCol = pkCols.First();
2935+
29062936 foreignKey = Settings.ForeignKeyProcessing(foreignKeys, fkTable, pkTable, fkCols.Any(x => x.col.IsNullable));
29072937
29082938 string pkTableHumanCaseWithSuffix = foreignKey.PkTableHumanCase(pkTable.Suffix);
@@ -2919,11 +2949,17 @@ SELECT SERVERPROPERTY('Edition') AS Edition,
29192949 foreignKey.IncludeRequiredAttribute ? ", Required" : string.Empty
29202950 );
29212951
2922- if (!checkForFkNameClashes && relationship == Relationship.OneToOne && foreignKey.IncludeReverseNavigation && fkCol.col.IsPrimaryKey)
2952+ if (!checkForFkNameClashes &&
2953+ relationship == Relationship.OneToOne &&
2954+ foreignKey.IncludeReverseNavigation &&
2955+ fkCols.All(x => x.col.IsPrimaryKey))
29232956 {
29242957 var principalEndAttribute = string.Format("ForeignKey(\"{0}\")", pkPropName);
2925- if (!fkCol.col.DataAnnotations.Contains(principalEndAttribute))
2926- fkCol.col.DataAnnotations.Add(principalEndAttribute);
2958+ foreach (var fk in fkCols)
2959+ {
2960+ if (!fk.col.DataAnnotations.Contains(principalEndAttribute))
2961+ fk.col.DataAnnotations.Add(principalEndAttribute);
2962+ }
29272963 }
29282964 }
29292965
@@ -2954,9 +2990,11 @@ SELECT SERVERPROPERTY('Edition') AS Edition,
29542990 mapKey = string.Format("\"{0}\"", fkCol.col.Name);
29552991 }
29562992
2957- // Always include fluent FK mapping even if only using data annotations
2958- fkCol.col.ConfigFk.Add(string.Format("{0};{1}", GetRelationship(relationship, fkCol.col, pkCol, pkPropName, fkPropName, manyToManyMapping, mapKey, foreignKey.CascadeOnDelete, foreignKey.IncludeReverseNavigation, foreignKey.IsNotEnforced),
2959- Settings.IncludeComments != CommentsStyle.None ? " // " + foreignKey.ConstraintName : string.Empty));
2993+ if (!Settings.UseDataAnnotations)
2994+ {
2995+ fkCol.col.ConfigFk.Add(string.Format("{0};{1}", GetRelationship(relationship, fkCol.col, pkCol, pkPropName, fkPropName, manyToManyMapping, mapKey, foreignKey.CascadeOnDelete, foreignKey.IncludeReverseNavigation, foreignKey.IsNotEnforced),
2996+ Settings.IncludeComments != CommentsStyle.None ? " // " + foreignKey.ConstraintName : string.Empty));
2997+ }
29602998
29612999 if(foreignKey.IncludeReverseNavigation)
29623000 pkTable.AddReverseNavigation(relationship, pkTableHumanCase, fkTable, fkPropName, string.Format("{0}.{1}", fkTable.Name, foreignKey.ConstraintName), foreignKeys);
@@ -3010,7 +3048,7 @@ SELECT SERVERPROPERTY('Edition') AS Edition,
30103048 break;
30113049 }
30123050
3013- if (withMany || pkCol.IsPrimaryKey)
3051+ if (withMany || pkCol.IsPrimaryKey || pkCol.IsUniqueConstraint || pkCol.IsUnique )
30143052 return fkCol.IsNullable || isNotEnforced ? "Optional" : "Required";
30153053
30163054 return "Many";
@@ -3467,10 +3505,11 @@ SELECT SERVERPROPERTY('Edition') AS Edition,
34673505 {
34683506 get
34693507 {
3470- return Columns.Where(x => x.IsPrimaryKey)
3471- .OrderBy(x => x.PrimaryKeyOrdinal)
3472- .ThenBy(x => x.Ordinal)
3473- .ToList();
3508+ return Columns
3509+ .Where(x => x.IsPrimaryKey)
3510+ .OrderBy(x => x.PrimaryKeyOrdinal)
3511+ .ThenBy(x => x.Ordinal)
3512+ .ToList();
34743513 }
34753514 }
34763515
0 commit comments