diff --git a/SQLite.CodeFirst.Console/Entity/Player.cs b/SQLite.CodeFirst.Console/Entity/Player.cs index 8e69fab..0750e49 100644 --- a/SQLite.CodeFirst.Console/Entity/Player.cs +++ b/SQLite.CodeFirst.Console/Entity/Player.cs @@ -9,5 +9,7 @@ public class Player : Person public int Number { get; set; } public virtual Team Team { get; set; } + + public virtual Player Mentor { get; set; } } } \ No newline at end of file diff --git a/SQLite.CodeFirst/Internal/Builder/CreateDatabaseStatementBuilder.cs b/SQLite.CodeFirst/Internal/Builder/CreateDatabaseStatementBuilder.cs index 2299e0a..65862a2 100644 --- a/SQLite.CodeFirst/Internal/Builder/CreateDatabaseStatementBuilder.cs +++ b/SQLite.CodeFirst/Internal/Builder/CreateDatabaseStatementBuilder.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Data.Entity.Core.Metadata.Edm; using System.Linq; -using SQLite.CodeFirst.Builder.NameCreators; using SQLite.CodeFirst.Statement; using SQLite.CodeFirst.Utility; @@ -27,29 +26,11 @@ public CreateDatabaseStatement BuildStatement() private IEnumerable GetCreateTableStatements() { + var associationTypeContainer = new AssociationTypeContainer(edmModel.AssociationTypes, edmModel.Container); + foreach (var entitySet in edmModel.Container.EntitySets) { - ICollection associationTypes = - edmModel.AssociationTypes.Where(a => a.Constraint.ToRole.Name == entitySet.Name).ToList(); - - IList associationTypeWrappers = new List(); - foreach (var associationType in associationTypes) - { - string fromTable = edmModel.Container.GetEntitySetByName(associationType.Constraint.FromRole.Name, true).Table; - string toTable = edmModel.Container.GetEntitySetByName(associationType.Constraint.ToRole.Name, true).Table; - - string fromTableName = TableNameCreator.CreateTableName(fromTable); - string toTableName = TableNameCreator.CreateTableName(toTable); - - associationTypeWrappers.Add(new AssociationTypeWrapper - { - AssociationType = associationType, - FromTableName = fromTableName, - ToTableName = toTableName - }); - } - - var tableStatementBuilder = new CreateTableStatementBuilder(entitySet, associationTypeWrappers); + var tableStatementBuilder = new CreateTableStatementBuilder(entitySet, associationTypeContainer); yield return tableStatementBuilder.BuildStatement(); } } diff --git a/SQLite.CodeFirst/Internal/Builder/CreateIndexStatementBuilder.cs b/SQLite.CodeFirst/Internal/Builder/CreateIndexStatementBuilder.cs index b29a4b8..ee32e6e 100644 --- a/SQLite.CodeFirst/Internal/Builder/CreateIndexStatementBuilder.cs +++ b/SQLite.CodeFirst/Internal/Builder/CreateIndexStatementBuilder.cs @@ -1,10 +1,8 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity.Core.Metadata.Edm; using System.Data.Entity.Infrastructure.Annotations; -using System.Globalization; using System.Linq; using SQLite.CodeFirst.Builder.NameCreators; using SQLite.CodeFirst.Extensions; diff --git a/SQLite.CodeFirst/Internal/Builder/CreateTableStatementBuilder.cs b/SQLite.CodeFirst/Internal/Builder/CreateTableStatementBuilder.cs index 69081d4..1f901cd 100644 --- a/SQLite.CodeFirst/Internal/Builder/CreateTableStatementBuilder.cs +++ b/SQLite.CodeFirst/Internal/Builder/CreateTableStatementBuilder.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Data.Entity.Core.Metadata.Edm; using SQLite.CodeFirst.Builder.NameCreators; using SQLite.CodeFirst.Statement; @@ -10,19 +9,19 @@ namespace SQLite.CodeFirst.Builder internal class CreateTableStatementBuilder : IStatementBuilder { private readonly EntitySet entitySet; - private readonly IEnumerable associationTypes; + private readonly AssociationTypeContainer associationTypeContainer; - public CreateTableStatementBuilder(EntitySet entitySet, IEnumerable associationTypes) + public CreateTableStatementBuilder(EntitySet entitySet, AssociationTypeContainer associationTypeContainer) { this.entitySet = entitySet; - this.associationTypes = associationTypes; + this.associationTypeContainer = associationTypeContainer; } public CreateTableStatement BuildStatement() { var simpleColumnCollection = new ColumnStatementCollectionBuilder(entitySet.ElementType.Properties).BuildStatement(); var primaryKeyStatement = new PrimaryKeyStatementBuilder(entitySet.ElementType.KeyMembers).BuildStatement(); - var foreignKeyCollection = new ForeignKeyStatementBuilder(associationTypes).BuildStatement(); + var foreignKeyCollection = new ForeignKeyStatementBuilder(associationTypeContainer.GetAssociationTypes(entitySet.Name)).BuildStatement(); var columnStatements = new List(); columnStatements.AddRange(simpleColumnCollection); diff --git a/SQLite.CodeFirst/Internal/Builder/ForeignKeyStatementBuilder.cs b/SQLite.CodeFirst/Internal/Builder/ForeignKeyStatementBuilder.cs index 5e88a57..e5fd81a 100644 --- a/SQLite.CodeFirst/Internal/Builder/ForeignKeyStatementBuilder.cs +++ b/SQLite.CodeFirst/Internal/Builder/ForeignKeyStatementBuilder.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Data.Entity.Core.Metadata.Edm; using System.Linq; using SQLite.CodeFirst.Statement; using SQLite.CodeFirst.Utility; @@ -8,9 +7,9 @@ namespace SQLite.CodeFirst.Builder { internal class ForeignKeyStatementBuilder : IStatementBuilder { - private readonly IEnumerable associationTypes; + private readonly IEnumerable associationTypes; - public ForeignKeyStatementBuilder(IEnumerable associationTypes) + public ForeignKeyStatementBuilder(IEnumerable associationTypes) { this.associationTypes = associationTypes; } @@ -27,10 +26,10 @@ private IEnumerable GetForeignKeyStatements() { yield return new ForeignKeyStatement { - ForeignKey = associationType.AssociationType.Constraint.ToProperties.Select(x => x.Name), + ForeignKey = associationType.ForeignKey, ForeignTable = associationType.FromTableName, - ForeignPrimaryKey = associationType.AssociationType.Constraint.FromProperties.Select(x => x.Name), - CascadeDelete = associationType.AssociationType.Constraint.FromRole.DeleteBehavior == OperationAction.Cascade + ForeignPrimaryKey = associationType.ForeignPrimaryKey, + CascadeDelete = associationType.CascadeDelete }; } } diff --git a/SQLite.CodeFirst/Internal/Builder/NameCreators/TableNameCreator.cs b/SQLite.CodeFirst/Internal/Builder/NameCreators/TableNameCreator.cs index 96cab32..0184762 100644 --- a/SQLite.CodeFirst/Internal/Builder/NameCreators/TableNameCreator.cs +++ b/SQLite.CodeFirst/Internal/Builder/NameCreators/TableNameCreator.cs @@ -7,6 +7,7 @@ internal static class TableNameCreator { public static string CreateTableName(string tableFromEntitySet) { + tableFromEntitySet = tableFromEntitySet.Trim(SpecialChars.EscapeCharOpen, SpecialChars.EscapeCharClose); return String.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", SpecialChars.EscapeCharOpen, tableFromEntitySet, SpecialChars.EscapeCharClose); } } diff --git a/SQLite.CodeFirst/Internal/Utility/AssociationTypeContainer.cs b/SQLite.CodeFirst/Internal/Utility/AssociationTypeContainer.cs new file mode 100644 index 0000000..e86d20f --- /dev/null +++ b/SQLite.CodeFirst/Internal/Utility/AssociationTypeContainer.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Data.Entity.Core.Metadata.Edm; +using System.Linq; + +namespace SQLite.CodeFirst.Utility +{ + internal class AssociationTypeContainer + { + private readonly IEnumerable sqliteAssociationTypes; + + public AssociationTypeContainer(IEnumerable associationTypes, EntityContainer container) + { + sqliteAssociationTypes = associationTypes.Select(associationType => new SqliteAssociationType(associationType, container)); + } + + public IEnumerable GetAssociationTypes(string entitySetName) + { + return sqliteAssociationTypes.Where(associationType => associationType.ToRoleEntitySetName == entitySetName); + } + } +} diff --git a/SQLite.CodeFirst/Internal/Utility/AssociationTypeWrapper.cs b/SQLite.CodeFirst/Internal/Utility/AssociationTypeWrapper.cs deleted file mode 100644 index c7c1a58..0000000 --- a/SQLite.CodeFirst/Internal/Utility/AssociationTypeWrapper.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Data.Entity.Core.Metadata.Edm; - -namespace SQLite.CodeFirst.Utility -{ - internal class AssociationTypeWrapper - { - public AssociationType AssociationType { get; set; } - public string FromTableName { get; set; } - public string ToTableName { get; set; } - } -} diff --git a/SQLite.CodeFirst/Internal/Utility/SqliteAssociationType.cs b/SQLite.CodeFirst/Internal/Utility/SqliteAssociationType.cs new file mode 100644 index 0000000..5322c98 --- /dev/null +++ b/SQLite.CodeFirst/Internal/Utility/SqliteAssociationType.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using System.Data.Entity.Core.Metadata.Edm; +using System.Linq; +using SQLite.CodeFirst.Builder.NameCreators; + +namespace SQLite.CodeFirst.Utility +{ + internal class SqliteAssociationType + { + private const string SelfReferencingPostfix = "Self"; + + public SqliteAssociationType(AssociationType associationType, EntityContainer container) + { + FromRoleEntitySetName = associationType.Constraint.FromRole.Name; + ToRoleEntitySetName = associationType.Constraint.ToRole.Name; + + string fromTable = container.GetEntitySetByName(FromRoleEntitySetName, true).Table; + string toTable; + + if (IsSelfReferencing(associationType)) + { + toTable = fromTable; + ToRoleEntitySetName = FromRoleEntitySetName; + } + else + { + toTable = container.GetEntitySetByName(ToRoleEntitySetName, true).Table; + } + + FromTableName = TableNameCreator.CreateTableName(fromTable); + ToTableName = TableNameCreator.CreateTableName(toTable); + ForeignKey = associationType.Constraint.ToProperties.Select(x => x.Name); + ForeignPrimaryKey = associationType.Constraint.FromProperties.Select(x => x.Name); + CascadeDelete = associationType.Constraint.FromRole.DeleteBehavior == OperationAction.Cascade; + } + + private static bool IsSelfReferencing(AssociationType associationType) + { + return associationType.Constraint.ToRole.Name.Remove(associationType.Constraint.ToRole.Name.Length - SelfReferencingPostfix.Length, SelfReferencingPostfix.Length) == associationType.Constraint.FromRole.Name; + } + + public string ToRoleEntitySetName { get; set; } + public string FromRoleEntitySetName { get; set; } + public IEnumerable ForeignKey { get; } + public string FromTableName { get; } + public string ToTableName { get; } + public IEnumerable ForeignPrimaryKey { get; } + public bool CascadeDelete { get; } + } +} \ No newline at end of file diff --git a/SQLite.CodeFirst/SQLite.CodeFirst.csproj b/SQLite.CodeFirst/SQLite.CodeFirst.csproj index 1f1c951..52aa4ff 100644 --- a/SQLite.CodeFirst/SQLite.CodeFirst.csproj +++ b/SQLite.CodeFirst/SQLite.CodeFirst.csproj @@ -89,13 +89,14 @@ + - +