diff --git a/changelog.txt b/changelog.txt
index a7e409d1e..af09e49c7 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -2,6 +2,7 @@
- Added a model fixup for when user doesn't use full enumeration name for a property's initial value in an entity
- Fix: Removed stray quote marks in default values for string properties (See https://github.com/msawczyn/EFDesigner/issues/86)
- Fix: Minimum string length was ignored when setting properties via text edit (See https://github.com/msawczyn/EFDesigner/issues/86)
+ - Fix: Required string identity property is not present in the constructor (See https://github.com/msawczyn/EFDesigner/issues/93)
1.3.0.4
- Fixed problematic code generation in constructors for classes having 1..1 associations (See https://github.com/msawczyn/EFDesigner/issues/74)
diff --git a/src/Dsl/GeneratedCode/SerializationHelper.cs b/src/Dsl/GeneratedCode/SerializationHelper.cs
index e7c39fc0e..7710c4514 100644
--- a/src/Dsl/GeneratedCode/SerializationHelper.cs
+++ b/src/Dsl/GeneratedCode/SerializationHelper.cs
@@ -506,7 +506,7 @@ public virtual ModelRoot LoadModel(DslModeling::SerializationResult serializatio
///// Partition in which the new ModelRoot instance will be created.
///// Name of the file from which the ModelRoot instance will be deserialized.
///// The root of the file that was loaded.
- // private void OnPostLoadModel(DslModeling::SerializationResult serializationResult, DslModeling::Partition partition, string fileName, ModelRoot modelRoot )
+ // private void OnPostLoadModel(DslModeling::SerializationResult serializationResult, DslModeling::Partition partition, string location, ModelRoot modelRoot )
this.OnPostLoadModel(serializationResult, partition, location, modelRoot);
if (serializationResult.Failed)
diff --git a/src/DslPackage/TextTemplates/EFDesigner.ttinclude b/src/DslPackage/TextTemplates/EFDesigner.ttinclude
index 85ffeddb3..7e07816a1 100644
--- a/src/DslPackage/TextTemplates/EFDesigner.ttinclude
+++ b/src/DslPackage/TextTemplates/EFDesigner.ttinclude
@@ -165,7 +165,7 @@ List GetRequiredParameters(ModelClass modelClass, bool? haveDefaults)
if (haveDefaults != true)
{
requiredParameters.AddRange(modelClass.AllRequiredAttributes
- .Where(x => !x.IsIdentity &&
+ .Where(x => (!x.IsIdentity || x.IdentityType == IdentityType.Manual) &&
!x.IsConcurrencyToken &&
x.SetterVisibility == SetterAccessModifier.Public &&
string.IsNullOrEmpty(x.InitialValue))
@@ -181,7 +181,7 @@ List GetRequiredParameters(ModelClass modelClass, bool? haveDefaults)
if (haveDefaults != false)
{
requiredParameters.AddRange(modelClass.AllRequiredAttributes
- .Where(x => !x.IsIdentity &&
+ .Where(x => (!x.IsIdentity || x.IdentityType == IdentityType.Manual) &&
!x.IsConcurrencyToken &&
x.SetterVisibility == SetterAccessModifier.Public &&
!string.IsNullOrEmpty(x.InitialValue))
@@ -199,7 +199,7 @@ List GetRequiredParameters(ModelClass modelClass, bool? haveDefaults)
List GetRequiredParameterNames(ModelClass modelClass)
{
List requiredParameterNames = modelClass.AllRequiredAttributes
- .Where(x => !x.IsIdentity && !x.IsConcurrencyToken && x.SetterVisibility == SetterAccessModifier.Public && string.IsNullOrEmpty(x.InitialValue))
+ .Where(x => (!x.IsIdentity || x.IdentityType == IdentityType.Manual) && && !x.IsConcurrencyToken && x.SetterVisibility == SetterAccessModifier.Public && string.IsNullOrEmpty(x.InitialValue))
.Select(x => x.Name.ToLower())
.ToList();
@@ -209,7 +209,7 @@ List GetRequiredParameterNames(ModelClass modelClass)
.Select(x => x.PropertyName.ToLower()));
requiredParameterNames.AddRange(modelClass.AllRequiredAttributes
- .Where(x => !x.IsIdentity && !x.IsConcurrencyToken && x.SetterVisibility == SetterAccessModifier.Public && !string.IsNullOrEmpty(x.InitialValue))
+ .Where(x => (!x.IsIdentity || x.IdentityType == IdentityType.Manual) && && !x.IsConcurrencyToken && x.SetterVisibility == SetterAccessModifier.Public && !string.IsNullOrEmpty(x.InitialValue))
.Select(x => x.Name.ToLower()));
return requiredParameterNames;
@@ -519,7 +519,7 @@ void WriteConstructor(ModelClass modelClass)
}
foreach (ModelAttribute requiredAttribute in modelClass.AllRequiredAttributes
- .Where(x => !x.IsIdentity &&
+ .Where(x => (!x.IsIdentity || x.IdentityType == IdentityType.Manual) &&
!x.IsConcurrencyToken &&
x.SetterVisibility == SetterAccessModifier.Public))
{
@@ -626,7 +626,7 @@ bool AllSuperclassesAreNullOrAbstract(ModelClass modelClass)
void WriteConstructorComments(ModelClass modelClass)
{
- foreach (ModelAttribute requiredAttribute in modelClass.AllRequiredAttributes.Where(x => !x.IsIdentity &&
+ foreach (ModelAttribute requiredAttribute in modelClass.AllRequiredAttributes.Where(x => (!x.IsIdentity || x.IdentityType == IdentityType.Manual) &&
!x.IsConcurrencyToken &&
x.SetterVisibility == SetterAccessModifier.Public))
Output($@"/// {requiredAttribute.Summary}");
diff --git a/src/Testing/Sandbox_EF6/EF6Designer.ttinclude b/src/Testing/Sandbox_EF6/EF6Designer.ttinclude
deleted file mode 100644
index d4bda84c8..000000000
--- a/src/Testing/Sandbox_EF6/EF6Designer.ttinclude
+++ /dev/null
@@ -1,740 +0,0 @@
-<#@ assembly name="System.Core"
-#><#@ assembly name="System.Data.Linq"
-#><#@ assembly name="EnvDTE"
-#><#@ assembly name="System.Xml"
-#><#@ assembly name="System.Xml.Linq"
-#><#@ import namespace="System.Collections.Generic"
-#><#@ import namespace="System.IO"
-#><#@ import namespace="System.Linq" #><#+
-
-// EFDesigner v1.3.0.4
-// Copyright (c) 2017-2019 Michael Sawczyn
-// https://github.com/msawczyn/EFDesigner
-
-void GenerateEF6(Manager manager, ModelRoot modelRoot)
-{
- // Entities
-
- foreach (ModelClass modelClass in modelRoot.Classes)
- {
- string dir = modelClass.IsDependentType ? modelRoot.StructOutputDirectory : modelRoot.EntityOutputDirectory;
- if (!string.IsNullOrEmpty(modelClass.OutputDirectory)) dir = modelClass.OutputDirectory;
- manager.StartNewFile(Path.Combine(dir, $"{modelClass.Name}.{modelRoot.FileNameMarker}.cs"));
- WriteClass(modelClass);
- }
-
- // Enums
-
- foreach (ModelEnum modelEnum in modelRoot.Enums)
- {
- string dir = !string.IsNullOrEmpty(modelEnum.OutputDirectory) ? modelEnum.OutputDirectory : modelRoot.EnumOutputDirectory;
- manager.StartNewFile(Path.Combine(dir, $"{modelEnum.Name}.{modelRoot.FileNameMarker}.cs"));
- WriteEnum(modelEnum);
- }
-
- // Context
-
- if (modelRoot.DatabaseInitializerType != DatabaseInitializerKind.None)
- {
- manager.StartNewFile(Path.Combine(modelRoot.ContextOutputDirectory, $"{modelRoot.EntityContainerName}DatabaseInitializer.{modelRoot.FileNameMarker}.cs"));
- WriteDatabaseInitializerEF6(modelRoot);
- }
-
- manager.StartNewFile(Path.Combine(modelRoot.ContextOutputDirectory, $"{modelRoot.EntityContainerName}DbMigrationConfiguration.{modelRoot.FileNameMarker}.cs"));
- WriteMigrationConfigurationEF6(modelRoot);
-
- manager.StartNewFile(Path.Combine(modelRoot.ContextOutputDirectory, $"{modelRoot.EntityContainerName}.{modelRoot.FileNameMarker}.cs"));
- WriteDbContextEF6(modelRoot);
-}
-
-List GetAdditionalUsingStatementsEF6(ModelRoot modelRoot)
-{
- List result = new List();
- List attributeTypes = modelRoot.Classes.SelectMany(c => c.Attributes).Select(a => a.Type).Distinct().ToList();
-
- if (attributeTypes.Any(t => t.IndexOf("Geometry", StringComparison.Ordinal) > -1 || t.IndexOf("Geography", StringComparison.Ordinal) > -1))
- {
- result.Add("using System.Data.Entity.Spatial;");
- }
-
- return result;
-}
-
-void WriteDatabaseInitializerEF6(ModelRoot modelRoot)
-{
- Output("using System.Data.Entity;");
- NL();
-
- BeginNamespace(modelRoot.Namespace);
-
- Output("/// ");
- if (modelRoot.DatabaseInitializerType == DatabaseInitializerKind.MigrateDatabaseToLatestVersion)
- Output($"public partial class {modelRoot.EntityContainerName}DatabaseInitializer : MigrateDatabaseToLatestVersion<{modelRoot.EntityContainerName}, {modelRoot.EntityContainerName}DbMigrationConfiguration>");
- else
- Output($"public partial class {modelRoot.EntityContainerName}DatabaseInitializer : {modelRoot.DatabaseInitializerType}<{modelRoot.EntityContainerName}>");
-
- Output("{");
- Output("}");
- EndNamespace(modelRoot.Namespace);
-}
-
-void WriteMigrationConfigurationEF6(ModelRoot modelRoot)
-{
- Output("using System.Data.Entity.Migrations;");
- NL();
-
- BeginNamespace(modelRoot.Namespace);
- Output("/// ");
- Output($"public sealed partial class {modelRoot.EntityContainerName}DbMigrationConfiguration : DbMigrationsConfiguration<{modelRoot.EntityContainerName}>");
-
- Output("{");
- Output("partial void Init();");
- NL();
-
- Output("/// ");
- Output($"public {modelRoot.EntityContainerName}DbMigrationConfiguration()");
- Output("{");
- Output($"AutomaticMigrationsEnabled = {modelRoot.AutomaticMigrationsEnabled.ToString().ToLower()};");
- Output("AutomaticMigrationDataLossAllowed = false;");
- Output("Init();");
- Output("}");
-
- Output("}");
- EndNamespace(modelRoot.Namespace);
-}
-
-void WriteDbContextEF6(ModelRoot modelRoot)
-{
- Output("using System;");
- Output("using System.Collections.Generic;");
- Output("using System.Linq;");
- Output("using System.ComponentModel.DataAnnotations.Schema;");
- Output("using System.Data.Entity;");
- Output("using System.Data.Entity.Infrastructure.Annotations;");
- NL();
-
- BeginNamespace(modelRoot.Namespace);
-
- if (!string.IsNullOrEmpty(modelRoot.Summary))
- {
- Output("/// ");
- WriteCommentBody(modelRoot.Summary);
- Output("/// ");
- if (!string.IsNullOrEmpty(modelRoot.Description))
- {
- Output("/// ");
- WriteCommentBody(modelRoot.Description);
- Output("/// ");
- }
- }
- else
- {
- Output("/// ");
- }
-
- Output($"{modelRoot.EntityContainerAccess.ToString().ToLower()} partial class {modelRoot.EntityContainerName} : System.Data.Entity.DbContext");
- Output("{");
-
- PluralizationService pluralizationService = ModelRoot.PluralizationService;
-
- /***********************************************************************/
- // generate DBSets
- /***********************************************************************/
-
- IEnumerable classesWithTables = null;
-
- switch (modelRoot.InheritanceStrategy)
- {
- case CodeStrategy.TablePerType:
- classesWithTables = modelRoot.Classes.Where(mc => !mc.IsDependentType).OrderBy(x => x.Name);
- break;
- case CodeStrategy.TablePerConcreteType:
- classesWithTables = modelRoot.Classes.Where(mc => !mc.IsDependentType && !mc.IsAbstract).OrderBy(x => x.Name);
- break;
- case CodeStrategy.TablePerHierarchy:
- classesWithTables = modelRoot.Classes.Where(mc => !mc.IsDependentType && mc.Superclass == null).OrderBy(x => x.Name);
- break;
- }
-
- if (classesWithTables != null)
- {
- Output("#region DbSets");
-
- foreach (ModelClass modelClass in modelRoot.Classes.Where(x => !x.IsDependentType).OrderBy(x => x.Name))
- {
- string dbSetName;
-
- if (!string.IsNullOrEmpty(modelClass.DbSetName))
- dbSetName = modelClass.DbSetName;
- else
- dbSetName = pluralizationService?.IsSingular(modelClass.Name) == true
- ? pluralizationService.Pluralize(modelClass.Name)
- : modelClass.Name;
-
- if (!string.IsNullOrEmpty(modelClass.Summary))
- {
- NL();
- Output("/// ");
- WriteCommentBody($"Repository for {modelClass.FullName} - {modelClass.Summary}");
- Output("/// ");
- }
- Output($"{modelRoot.DbSetAccess.ToString().ToLower()} virtual System.Data.Entity.DbSet<{modelClass.FullName}> {dbSetName} {{ get; set; }}");
- }
-
- Output("#endregion DbSets");
- NL();
- }
-
- Output("#region Constructors");
- NL();
- Output("partial void CustomInit();");
- NL();
-
- /***********************************************************************/
- // constructors
- /***********************************************************************/
-
- if (!string.IsNullOrEmpty(modelRoot.ConnectionString) || !string.IsNullOrEmpty(modelRoot.ConnectionStringName))
- {
- string connectionString = string.IsNullOrEmpty(modelRoot.ConnectionString)
- ? $"Name={modelRoot.ConnectionStringName}"
- : modelRoot.ConnectionString;
-
- Output("/// ");
- Output("/// Default connection string");
- Output("/// ");
- Output($"public static string ConnectionString {{ get; set; }} = @\"{connectionString}\";");
-
- Output("/// ");
- Output($"public {modelRoot.EntityContainerName}() : base(ConnectionString)");
- Output("{");
- Output($"Configuration.LazyLoadingEnabled = {modelRoot.LazyLoadingEnabled.ToString().ToLower()};");
- Output($"Configuration.ProxyCreationEnabled = {modelRoot.ProxyGenerationEnabled.ToString().ToLower()};");
- if (modelRoot.DatabaseInitializerType == DatabaseInitializerKind.None)
- Output($"System.Data.Entity.Database.SetInitializer<{modelRoot.EntityContainerName}>(null);");
- else
- Output($"System.Data.Entity.Database.SetInitializer<{modelRoot.EntityContainerName}>(new {modelRoot.EntityContainerName}DatabaseInitializer());");
- Output("CustomInit();");
- Output("}");
- NL();
- }
- else
- {
- Output($"#warning Default constructor not generated for {modelRoot.EntityContainerName} since no default connection string was specified in the model");
- NL();
- }
-
- Output("/// ");
- Output($"public {modelRoot.EntityContainerName}(string connectionString) : base(connectionString)");
- Output("{");
- Output($"Configuration.LazyLoadingEnabled = {modelRoot.LazyLoadingEnabled.ToString().ToLower()};");
- Output($"Configuration.ProxyCreationEnabled = {modelRoot.ProxyGenerationEnabled.ToString().ToLower()};");
- if (modelRoot.DatabaseInitializerType == DatabaseInitializerKind.None)
- Output($"System.Data.Entity.Database.SetInitializer<{modelRoot.EntityContainerName}>(null);");
- else
- Output($"System.Data.Entity.Database.SetInitializer<{modelRoot.EntityContainerName}>(new {modelRoot.EntityContainerName}DatabaseInitializer());");
- Output("CustomInit();");
- Output("}");
- NL();
-
- Output("/// ");
- Output($"public {modelRoot.EntityContainerName}(string connectionString, System.Data.Entity.Infrastructure.DbCompiledModel model) : base(connectionString, model)");
- Output("{");
- Output($"Configuration.LazyLoadingEnabled = {modelRoot.LazyLoadingEnabled.ToString().ToLower()};");
- Output($"Configuration.ProxyCreationEnabled = {modelRoot.ProxyGenerationEnabled.ToString().ToLower()};");
- if (modelRoot.DatabaseInitializerType == DatabaseInitializerKind.None)
- Output($"System.Data.Entity.Database.SetInitializer<{modelRoot.EntityContainerName}>(null);");
- else
- Output($"System.Data.Entity.Database.SetInitializer<{modelRoot.EntityContainerName}>(new {modelRoot.EntityContainerName}DatabaseInitializer());");
- Output("CustomInit();");
- Output("}");
- NL();
-
- Output("/// ");
- Output($"public {modelRoot.EntityContainerName}(System.Data.Common.DbConnection existingConnection, bool contextOwnsConnection) : base(existingConnection, contextOwnsConnection)");
- Output("{");
- Output($"Configuration.LazyLoadingEnabled = {modelRoot.LazyLoadingEnabled.ToString().ToLower()};");
- Output($"Configuration.ProxyCreationEnabled = {modelRoot.ProxyGenerationEnabled.ToString().ToLower()};");
- if (modelRoot.DatabaseInitializerType == DatabaseInitializerKind.None)
- Output($"System.Data.Entity.Database.SetInitializer<{modelRoot.EntityContainerName}>(null);");
- else
- Output($"System.Data.Entity.Database.SetInitializer<{modelRoot.EntityContainerName}>(new {modelRoot.EntityContainerName}DatabaseInitializer());");
- Output("CustomInit();");
- Output("}");
- NL();
-
- Output("/// ");
- Output($"public {modelRoot.EntityContainerName}(System.Data.Common.DbConnection existingConnection, System.Data.Entity.Infrastructure.DbCompiledModel model, bool contextOwnsConnection) : base(existingConnection, model, contextOwnsConnection)");
- Output("{");
- Output($"Configuration.LazyLoadingEnabled = {modelRoot.LazyLoadingEnabled.ToString().ToLower()};");
- Output($"Configuration.ProxyCreationEnabled = {modelRoot.ProxyGenerationEnabled.ToString().ToLower()};");
- if (modelRoot.DatabaseInitializerType == DatabaseInitializerKind.None)
- Output($"System.Data.Entity.Database.SetInitializer<{modelRoot.EntityContainerName}>(null);");
- else
- Output($"System.Data.Entity.Database.SetInitializer<{modelRoot.EntityContainerName}>(new {modelRoot.EntityContainerName}DatabaseInitializer());");
- Output("CustomInit();");
- Output("}");
- NL();
-
- Output("/// ");
- Output($"public {modelRoot.EntityContainerName}(System.Data.Entity.Infrastructure.DbCompiledModel model) : base(model)");
- Output("{");
- Output($"Configuration.LazyLoadingEnabled = {modelRoot.LazyLoadingEnabled.ToString().ToLower()};");
- Output($"Configuration.ProxyCreationEnabled = {modelRoot.ProxyGenerationEnabled.ToString().ToLower()};");
- if (modelRoot.DatabaseInitializerType == DatabaseInitializerKind.None)
- Output($"System.Data.Entity.Database.SetInitializer<{modelRoot.EntityContainerName}>(null);");
- else
- Output($"System.Data.Entity.Database.SetInitializer<{modelRoot.EntityContainerName}>(new {modelRoot.EntityContainerName}DatabaseInitializer());");
- Output("CustomInit();");
- Output("}");
- NL();
-
- Output("/// ");
- Output($"public {modelRoot.EntityContainerName}(System.Data.Entity.Core.Objects.ObjectContext objectContext, bool dbContextOwnsObjectContext) : base(objectContext, dbContextOwnsObjectContext)");
- Output("{");
- Output($"Configuration.LazyLoadingEnabled = {modelRoot.LazyLoadingEnabled.ToString().ToLower()};");
- Output($"Configuration.ProxyCreationEnabled = {modelRoot.ProxyGenerationEnabled.ToString().ToLower()};");
- if (modelRoot.DatabaseInitializerType == DatabaseInitializerKind.None)
- Output($"System.Data.Entity.Database.SetInitializer<{modelRoot.EntityContainerName}>(null);");
- else
- Output($"System.Data.Entity.Database.SetInitializer<{modelRoot.EntityContainerName}>(new {modelRoot.EntityContainerName}DatabaseInitializer());");
- Output("CustomInit();");
- Output("}");
- NL();
- Output("#endregion Constructors");
- NL();
-
- /***********************************************************************/
- // Experimental
- /***********************************************************************/
- /*
- Output("private void HandleOrphans()");
- Output("{");
- Output("ChangeTracker.DetectChanges();");
- Output("bool wasLazyLoading = Configuration.LazyLoadingEnabled;");
- Output("Configuration.LazyLoadingEnabled = false;");
- NL();
- Output("try");
- Output("{");
-
- Dictionary> orphanRemoval = new Dictionary>();
- foreach (ModelClass modelClass in modelRoot.Classes.Where(x => !x.IsDependentType).OrderBy(x => x.Name))
- {
- if (!orphanRemoval.ContainsKey(modelClass.DbSetName))
- orphanRemoval.Add(modelClass.DbSetName, new List());
- foreach (NavigationProperty navigationProperty in modelClass.AllRequiredNavigationProperties())
- {
- Association association = navigationProperty.AssociationObject;
- if (!string.IsNullOrEmpty(navigationProperty.PropertyName))
- {
- if (association is BidirectionalAssociation && association.SourceMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.One ||
- (association is UnidirectionalAssociation && (association.TargetMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.One &&
- association.SourceMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One)))
- {
- orphanRemoval[modelClass.DbSetName].Add($"{modelClass.DbSetName}.RemoveRange({modelClass.DbSetName}.Local.Where(x => Entry(x).State != EntityState.Deleted && x.{navigationProperty.PropertyName} == null));");
- }
- else if (association is UnidirectionalAssociation &&
- association.TargetMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany)
- {
- orphanRemoval[modelClass.DbSetName].Add($"{modelClass.DbSetName}.RemoveRange({modelClass.DbSetName}.Local.Where(x => Entry(x).State != EntityState.Deleted).Except({association.Source.DbSetName}.Local.Where(x => Entry(x).State != EntityState.Deleted).SelectMany(x => x.{association.TargetPropertyName})));");
- }
- else if (association is UnidirectionalAssociation &&
- !association.Source.IsDependentType && !association.Target.IsDependentType &&
- (association.TargetMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne ||
- association.TargetMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.One))
- {
- orphanRemoval[modelClass.DbSetName].Add($"{modelClass.DbSetName}.RemoveRange({modelClass.DbSetName}.Local.Where(x => Entry(x).State != EntityState.Deleted).Except({association.Source.DbSetName}.Local.Where(x => Entry(x).State != EntityState.Deleted).Select(x => x.{association.TargetPropertyName})));");
- }
- else if (association is BidirectionalAssociation bidirectional &&
- !association.Source.IsDependentType && !association.Target.IsDependentType &&
- bidirectional.SourceMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne)
- {
- orphanRemoval[modelClass.DbSetName].Add($"{modelClass.DbSetName}.RemoveRange({modelClass.DbSetName}.Local.Where(x => Entry(x).State != EntityState.Deleted).Except({bidirectional.Target.DbSetName}.Local.Where(x => Entry(x).State != EntityState.Deleted).Select(x => x.{bidirectional.SourcePropertyName})));");
- }
- }
- }
- }
-
- foreach (string key in orphanRemoval.Keys.Where(k => orphanRemoval[k].Any()))
- {
- Output($"if ({key}.Local.Any(x => Entry(x).State != EntityState.Deleted))");
- Output("{");
- foreach (string action in orphanRemoval[key])
- {
- Output(action);
- }
- Output("}");
- }
-
- Output("}");
- Output("finally");
- Output("{");
- Output("Configuration.LazyLoadingEnabled = wasLazyLoading;");
- Output("}");
-
- Output("}");
- NL();
- */
-
- /***********************************************************************/
- // OnModelCreating
- /***********************************************************************/
- Output("partial void OnModelCreatingImpl(System.Data.Entity.DbModelBuilder modelBuilder);");
- Output("partial void OnModelCreatedImpl(System.Data.Entity.DbModelBuilder modelBuilder);");
- NL();
-
- Output("/// ");
- Output("protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)");
- Output("{");
- Output("base.OnModelCreating(modelBuilder);");
- Output("OnModelCreatingImpl(modelBuilder);");
- NL();
-
- Output($"modelBuilder.HasDefaultSchema(\"{modelRoot.DatabaseSchema}\");");
-
- List segments = new List();
-
- Sawczyn.EFDesigner.EFModel.Multiplicity[] singles = { Sawczyn.EFDesigner.EFModel.Multiplicity.One, Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne };
- Sawczyn.EFDesigner.EFModel.Multiplicity[] multiples = { Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany };
- List visited = new List();
- List foreignKeyColumns = new List();
-
- foreach (ModelClass modelClass in modelRoot.Classes.OrderBy(x => x.Name))
- {
- segments.Clear();
- foreignKeyColumns.Clear();
- NL();
-
- // class level
- bool isDependent = modelClass.IsDependentType;
- segments.Add($"modelBuilder.{(isDependent ? "ComplexType" : "Entity")}<{modelClass.FullName}>()");
-
- // note: this must come before the 'ToTable' call or there's a runtime error
- if (modelRoot.InheritanceStrategy == CodeStrategy.TablePerConcreteType && modelClass.Superclass != null)
- segments.Add("Map(x => x.MapInheritedProperties())");
-
- if (classesWithTables.Contains(modelClass))
- {
- if (modelClass.DatabaseSchema == modelClass.ModelRoot.DatabaseSchema)
- segments.Add($"ToTable(\"{modelClass.TableName}\")");
- else
- segments.Add($"ToTable(\"{modelClass.TableName}\", \"{modelClass.DatabaseSchema}\")");
-
- // primary key code segments must be output last, since HasKey returns a different type
- List identityAttributes = modelClass.IdentityAttributes.ToList();
- if (identityAttributes.Count() == 1)
- segments.Add($"HasKey(t => t.{identityAttributes[0].Name})");
- else if (identityAttributes.Count() > 1)
- segments.Add($"HasKey(t => new {{ t.{string.Join(", t.", identityAttributes.Select(ia => ia.Name))} }})");
- }
-
- foreach (ModelAttribute transient in modelClass.Attributes.Where(x => !x.Persistent))
- segments.Add($"Ignore(t => t.{transient.Name})");
-
- if (segments.Count > 1)
- {
- if (modelRoot.ChopMethodChains)
- OutputChopped(segments);
- else
- Output(string.Join(".", segments) + ";");
- }
-
- // indexed properties
- foreach (ModelAttribute indexed in modelClass.Attributes.Where(x => x.Indexed && !x.IsIdentity))
- {
- segments.Clear();
- string attributeName = !indexed.AutoProperty ? $"_{indexed.Name}" : indexed.Name;
- segments.Add($"modelBuilder.Entity<{modelClass.FullName}>().HasIndex(t => t.{attributeName})");
- if (indexed.IndexedUnique) segments.Add("IsUnique()");
- if (segments.Count > 1)
- {
- if (modelRoot.ChopMethodChains)
- OutputChopped(segments);
- else
- Output(string.Join(".", segments) + ";");
- }
- }
-
- // attribute level
- foreach (ModelAttribute modelAttribute in modelClass.Attributes.Where(x => x.Persistent && !SpatialTypes.Contains(x.Type)))
- {
- segments.Clear();
-
- if (modelAttribute.MaxLength > 0)
- segments.Add($"HasMaxLength({modelAttribute.MaxLength})");
- if (modelAttribute.Required)
- segments.Add("IsRequired()");
- if (modelAttribute.ColumnName != modelAttribute.Name && !string.IsNullOrEmpty(modelAttribute.ColumnName))
- segments.Add($"HasColumnName(\"{modelAttribute.ColumnName}\")");
- if (!string.IsNullOrEmpty(modelAttribute.ColumnType) && modelAttribute.ColumnType.ToLowerInvariant() != "default")
- segments.Add($"HasColumnType(\"{modelAttribute.ColumnType}\")");
- if (modelAttribute.Indexed && !modelAttribute.IsIdentity)
- segments.Add("HasColumnAnnotation(\"Index\", new IndexAnnotation(new IndexAttribute()))");
- if (modelAttribute.IsConcurrencyToken)
- segments.Add("IsRowVersion()");
- if (modelAttribute.IsIdentity)
- {
- if (modelAttribute.IdentityType == IdentityType.AutoGenerated)
- segments.Add("HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)");
- else
- segments.Add("HasDatabaseGeneratedOption(DatabaseGeneratedOption.None)");
- }
-
- if (segments.Any())
- {
- segments.Insert(0, $"modelBuilder.{(isDependent ? "ComplexType" : "Entity")}<{modelClass.FullName}>()");
- segments.Insert(1, $"Property(t => t.{modelAttribute.Name})");
-
- if (modelRoot.ChopMethodChains)
- OutputChopped(segments);
- else
- Output(string.Join(".", segments) + ";");
- }
- }
-
- if (!isDependent)
- {
- // Navigation endpoints are distingished as Source and Target. They are also distinguished as Principal
- // and Dependent. How do these map?
- // In the case of one-to-one or zero-to-one-to-zero-to-one, it's model dependent and the user has to tell us
- // In all other cases, we can tell by the cardinalities of the associations
- // What matters is the Principal and Dependent classifications, so we look at those.
- // Source and Target are accidents of where the user started drawing the association.
-
- // navigation properties
- foreach (UnidirectionalAssociation association in Association.GetLinksToTargets(modelClass).OfType().Where(x => !x.Target.IsDependentType))
- {
- if (visited.Contains(association)) continue;
- visited.Add(association);
-
- segments.Clear();
- segments.Add($"modelBuilder.Entity<{modelClass.FullName}>()");
-
- switch (association.TargetMultiplicity) // realized by property on source
- {
- case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany:
- segments.Add($"HasMany(x => x.{association.TargetPropertyName})");
- break;
- case Sawczyn.EFDesigner.EFModel.Multiplicity.One:
- segments.Add($"HasRequired(x => x.{association.TargetPropertyName})");
- break;
- case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne:
- segments.Add($"HasOptional(x => x.{association.TargetPropertyName})");
- break;
- //case Sawczyn.EFDesigner.EFModel.Multiplicity.OneMany:
- // segments.Add($"HasMany(x => x.{association.TargetPropertyName})");
- // break;
- }
-
- switch (association.SourceMultiplicity) // realized by property on target, but no property on target
- {
- case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany:
- segments.Add("WithMany()");
- if (association.TargetMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany)
- {
- if (modelClass == association.Source)
- {
- segments.Add("Map(x => { " +
- $@"x.ToTable(""{association.Source.Name}_x_{association.TargetPropertyName}""); " +
- $@"x.MapLeftKey(""{association.Source.Name}_{association.Source.AllAttributes.FirstOrDefault(a => a.IsIdentity)?.Name}""); " +
- $@"x.MapRightKey(""{association.Target.Name}_{association.Target.AllAttributes.FirstOrDefault(a => a.IsIdentity)?.Name}""); " +
- "})");
- }
- else
- {
- segments.Add("Map(x => { " +
- $@"x.ToTable(""{association.Source.Name}_x_{association.TargetPropertyName}""); " +
- $@"x.MapRightKey(""{association.Source.Name}_{association.Source.AllAttributes.FirstOrDefault(a => a.IsIdentity)?.Name}""); " +
- $@"x.MapLeftKey(""{association.Target.Name}_{association.Target.AllAttributes.FirstOrDefault(a => a.IsIdentity)?.Name}""); " +
- "})");
- }
- }
- break;
- case Sawczyn.EFDesigner.EFModel.Multiplicity.One:
- if (association.TargetMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.One)
- {
- if (association.TargetRole == EndpointRole.Dependent)
- segments.Add("WithRequiredDependent()");
- else
- segments.Add("WithRequiredPrincipal()");
- }
- else
- {
- segments.Add("WithRequired()");
- }
-
- break;
- case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne:
- if (association.TargetMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne)
- {
- if (association.TargetRole == EndpointRole.Dependent)
- segments.Add("WithOptionalDependent()");
- else
- segments.Add("WithOptionalPrincipal()");
- }
- else
- {
- segments.Add("WithOptional()");
- }
-
- break;
- //case Sawczyn.EFDesigner.EFModel.Multiplicity.OneMany:
- // segments.Add("HasMany()");
- // break;
- }
-
- string foreignKeySegment = CreateForeignKeyColumnSegmentEF6(association, foreignKeyColumns);
- if (foreignKeySegment != null) segments.Add(foreignKeySegment);
-
- // Certain associations cascade delete automatically. Also, the user may ask for it.
- // We only generate a cascade delete call if the user asks for it.
- if ((association.TargetDeleteAction != DeleteAction.Default && association.TargetRole == EndpointRole.Principal) ||
- (association.SourceDeleteAction != DeleteAction.Default && association.SourceRole == EndpointRole.Principal))
- {
- string willCascadeOnDelete = (association.TargetDeleteAction == DeleteAction.Cascade).ToString().ToLowerInvariant();
- segments.Add($"WillCascadeOnDelete({willCascadeOnDelete})");
- }
-
- if (modelRoot.ChopMethodChains)
- OutputChopped(segments);
- else
- Output(string.Join(".", segments) + ";");
- }
-
- foreach (BidirectionalAssociation association in Association.GetLinksToSources(modelClass).OfType())
- {
- if (visited.Contains(association)) continue;
- visited.Add(association);
-
- segments.Clear();
- segments.Add($"modelBuilder.Entity<{modelClass.FullName}>()");
-
- switch (association.SourceMultiplicity) // realized by property on target
- {
- case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany:
- segments.Add($"HasMany(x => x.{association.SourcePropertyName})");
- break;
- case Sawczyn.EFDesigner.EFModel.Multiplicity.One:
- segments.Add($"HasRequired(x => x.{association.SourcePropertyName})");
- break;
- case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne:
- segments.Add($"HasOptional(x => x.{association.SourcePropertyName})");
- break;
- //one or more constraint not supported in EF. TODO: make this possible ... later
- //case Sawczyn.EFDesigner.EFModel.Multiplicity.OneMany:
- // segments.Add($"HasMany(x => x.{association.SourcePropertyName})");
- // break;
- }
-
- switch (association.TargetMultiplicity) // realized by property on source
- {
- case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany:
- segments.Add($"WithMany(x => x.{association.TargetPropertyName})");
- if (association.SourceMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany)
- {
- if (modelClass == association.Source)
- {
- segments.Add("Map(x => { " +
- $@"x.ToTable(""{association.SourcePropertyName}_x_{association.TargetPropertyName}""); " +
- $@"x.MapLeftKey(""{association.Source.Name}_{association.Source.AllAttributes.FirstOrDefault(a => a.IsIdentity)?.Name}""); " +
- $@"x.MapRightKey(""{association.Target.Name}_{association.Target.AllAttributes.FirstOrDefault(a => a.IsIdentity)?.Name}""); " +
- "})");
- }
- else
- {
- segments.Add("Map(x => { " +
- $@"x.ToTable(""{association.SourcePropertyName}_x_{association.TargetPropertyName}""); " +
- $@"x.MapRightKey(""{association.Source.Name}_{association.Source.AllAttributes.FirstOrDefault(a => a.IsIdentity)?.Name}""); " +
- $@"x.MapLeftKey(""{association.Target.Name}_{association.Target.AllAttributes.FirstOrDefault(a => a.IsIdentity)?.Name}""); " +
- "})");
- }
- }
- break;
- case Sawczyn.EFDesigner.EFModel.Multiplicity.One:
- if (association.SourceMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.One)
- {
- if (association.SourceRole == EndpointRole.Dependent)
- segments.Add($"WithRequiredDependent(x => x.{association.TargetPropertyName})");
- else
- segments.Add($"WithRequiredPrincipal(x => x.{association.TargetPropertyName})");
- }
- else
- {
- segments.Add($"WithRequired(x => x.{association.TargetPropertyName})");
- }
-
- break;
- case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne:
- if (association.SourceMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne)
- {
- if (association.SourceRole == EndpointRole.Dependent)
- segments.Add($"WithOptionalDependent(x => x.{association.TargetPropertyName})");
- else
- segments.Add($"WithOptionalPrincipal(x => x.{association.TargetPropertyName})");
- }
- else
- {
- segments.Add($"WithOptional(x => x.{association.TargetPropertyName})");
- }
-
- break;
- //one or more constraint not supported in EF. TODO: make this possible ... later
- //case Sawczyn.EFDesigner.EFModel.Multiplicity.OneMany:
- // segments.Add($"HasMany(x => x.{association.TargetPropertyName})");
- // break;
- }
-
- string foreignKeySegment = CreateForeignKeyColumnSegmentEF6(association, foreignKeyColumns);
- if (foreignKeySegment != null) segments.Add(foreignKeySegment);
-
- if (association.SourceDeleteAction != DeleteAction.Default)
- {
- string willCascadeOnDelete = (association.SourceDeleteAction == DeleteAction.Cascade).ToString().ToLowerInvariant();
- segments.Add($"WillCascadeOnDelete({willCascadeOnDelete})");
- }
-
- if (modelRoot.ChopMethodChains)
- OutputChopped(segments);
- else
- Output(string.Join(".", segments) + ";");
- }
- }
- }
-
- NL();
-
- Output("OnModelCreatedImpl(modelBuilder);");
- Output("}");
-
- Output("}");
-
- EndNamespace(modelRoot.Namespace);
-}
-
-string CreateForeignKeyColumnSegmentEF6(Association association, List foreignKeyColumns)
-{
- // foreign key definitions always go in the table representing the Dependent end of the association
- // if there is no dependent end (i.e., many-to-many), there are no foreign keys
- string nameBase = string.Empty;
-
- if (association.SourceRole == EndpointRole.Dependent)
- nameBase = association.TargetPropertyName;
- else if (association.TargetRole == EndpointRole.Dependent)
- nameBase = association is BidirectionalAssociation b ? b.SourcePropertyName : $"{association.Source.Name}.{association.TargetPropertyName}";
- else
- return null;
-
- string columnName = $"{nameBase}_Id";
- if (foreignKeyColumns.Contains(columnName))
- {
- int index = 0;
- do
- {
- columnName = $"{nameBase}{++index}_Id";
- } while (foreignKeyColumns.Contains(columnName));
- }
- foreignKeyColumns.Add(columnName);
- return $@"Map(x => x.MapKey(""{columnName}""))";
-}
-
-#>
\ No newline at end of file
diff --git a/src/Testing/Sandbox_EF6/Sandbox_EF6.csproj b/src/Testing/Sandbox_EF6/Sandbox_EF6.csproj
index 130ca5ab1..5b79c4616 100644
--- a/src/Testing/Sandbox_EF6/Sandbox_EF6.csproj
+++ b/src/Testing/Sandbox_EF6/Sandbox_EF6.csproj
@@ -66,7 +66,6 @@
Designer
-
EFModel.efmodel