protected override void GenerateManyToMany(ITable table) { var tableNamespace = TableNamespace(table); var tableClassName = TableClassName(table); var tableClass = GenerationContext.FindClass(tableClassName, tableNamespace); var manyToManyList = table.ManyToMany().ToList(); manyToManyList.ForEach(fk => { // get the other foreign key of this many to many. var otherFk = fk.ForeignKeyColumn.Table.ForeignKeys.FirstOrDefault(t => t != fk); // other table attached to this many to many. var otherPk = otherFk.PrimaryKeyColumn.Table; // skip if other table is not being generated. if (!TablesToGenerate.Contains(otherPk)) { return; } // pluralize this name. var propName = ManyToManyPropertyName(table, fk, otherFk); propName = tableClass.GetUniqueMemberName(propName); // the type of the property. var pocoType = TableClassFullName(otherPk); var propType = $"System.Collections.Generic.ICollection<{pocoType}>"; var defaultValue = $"new {CollectionInstanceType()}<{pocoType}>()"; // generate property :) tableClass.Property(p => p.Virtual(true).Type(propType).Name(propName).DefaultValue(defaultValue).Comment("Many to Many").Meta(Tuple.Create(NavigationKind.ManyToMany, fk))); }); }
protected override void GenerateManyToMany(ITable table) { var tableNamespace = TableNamespace(table); var tableClassName = TableClassName(table); var tableClass = GenerationContext.FindClass(tableClassName, tableNamespace); var manyToManyList = table.ManyToMany().ToList(); manyToManyList.ForEach(fk => { if (!TablesToGenerate.Contains(fk.ForeignKeyColumn.Table)) { return; } // get the poco of the many to many. var manyToManyPocoFullClass = TableClassFullName(fk.ForeignKeyColumn.Table); // pluralize this name. var propName = Pluralize(fk.ForeignKeyColumn.Table.Name); propName = tableClass.GetUniqueMemberName(propName); // the type of the property. var propType = $"System.Collections.Generic.ICollection<{manyToManyPocoFullClass}>"; var defaultValue = $"new {CollectionInstanceType()}<{manyToManyPocoFullClass}>()"; // generate property :) tableClass.Property(p => p.Type(propType).Name(propName).DefaultValue(defaultValue).Comment("Many to Many").Meta(fk)); }); }
protected virtual void GenerateForeignKeys(ITable table) { var tableNamespace = TableNamespace(table); var tableClassName = TableClassName(table); var tableClass = GenerationContext.FindClass(tableClassName, tableNamespace); table.ForeignKeys.ForEach(fk => { if (!TablesToGenerate.Contains(fk.PrimaryKeyColumn.Table)) { return; } var propName = ForeignKeyPropertyName(fk); if (tableClass.HasMemberWithName(propName)) { var tempPropName = ForeignKeyPropertyName(fk, true); if (!tableClass.HasMemberWithName(tempPropName)) { propName = tempPropName; } } propName = tableClass.GetUniqueMemberName(propName); var foreignKeyTypeName = TableClassFullName(fk.PrimaryKeyColumn.Table); tableClass.Property(foreignKeyProp => foreignKeyProp.Virtual(ForeignKeysShouldBeVirtual()).Type(foreignKeyTypeName).Name(propName).Comment("Foreign Key").Meta(fk)); }); }
protected virtual void GenerateHasMany(ITable table) { var tableNamespace = TableNamespace(table); var tableClassName = TableClassName(table); var tableClass = GenerationContext.FindClass(tableClassName, tableNamespace); var hasManyList = table.HasMany().ToList(); hasManyList.ForEach(fk => { if (!TablesToGenerate.Contains(fk.ForeignKeyColumn.Table)) { return; } var hasMoreThanOne = table.HasMany().Count(t => t.ForeignKeyColumn.Table == fk.ForeignKeyColumn.Table) > 1; var propName = HasManyPropertyName(fk, hasMoreThanOne); propName = tableClass.GetUniqueMemberName(propName); var pocoType = TableClassFullName(fk.ForeignKeyColumn.Table); var propType = $"System.Collections.Generic.ICollection<{pocoType}>"; var defaultValue = $"new {CollectionInstanceType()}<{pocoType}>()"; tableClass.Property(p => p.Virtual(HasManyShouldBeVirtual()).Type(propType).Name(propName).DefaultValue(defaultValue).Comment("Has Many").Meta(fk)); }); }
private void GenerateFluentConfigurations() { TablesToGenerate.ForEach(table => { GenerateEntityFluentConfiguration(table); }); }
private void GenerateFluentConfigurations() { TablesToGenerate.ForEach(table => { if (Options.OutputToSingleFile) { GenerationContext.SingleFile(fb => GenerateEntityFluentConfiguration(table, fb)); } else { GenerationContext.File(fb => GenerateEntityFluentConfiguration(table, fb)); } }); }
private void EachTableHooks() { DynamicAssemblies.ForEach(a => { var eachTableServices = a.GetTypes() .Where(t => t.IsClass && typeof(ITableInterceptor).IsAssignableFrom(t)) .Select(t => (ITableInterceptor)Activator.CreateInstance(t, (IGenerator)this)) .ToList(); TablesToGenerate.ForEach(table => { eachTableServices.ForEach(t => t.InterceptTable(table)); }); }); }
protected virtual void GenerateOneToOnes(ITable table) { var tableNamespace = TableNamespace(table); var tableClassName = TableClassName(table); var tableClass = GenerationContext.FindClass(tableClassName, tableNamespace); table.OneToOne().ToList().ForEach(fk => { if (!TablesToGenerate.Contains(fk.ForeignKeyColumn.Table)) { return; } var propName = OneToOnePropertyName(fk); propName = tableClass.GetUniqueMemberName(propName); var propType = TableClassFullName(fk.ForeignKeyColumn.Table); tableClass.Property(p => p.Virtual(OneToShouldBeVirtual()).Type(propType).Name(propName).Comment("One to One").Meta(fk)); }); }
protected void GenerateEntities() { var tables = TablesToGenerate.ToList(); tables.ForEach(table => { GenerateEntityInterface(table); GenerateEntity(table); GenerateModelInterface(table); GenerateModel(table); GenerateModelExtensions(table); }); // generate foreign keys and navigation properties. tables.ForEach(table => { GenerateForeignKeys(table); GenerateOneToOnes(table); GenerateHasMany(table); GenerateManyToMany(table); }); }
protected void GenerateEntities() { var tables = TablesToGenerate.ToList(); tables.ForEach(table => { if (Options.OutputToSingleFile) { GenerationContext.SingleFile(fb => { var filePath = $"{Options.OutputDir}{Path.DirectorySeparatorChar}{Options.OutputSingleFileName}"; fb.Path(filePath); GenerateEntityInterface(table, fb); GenerateEntity(table, fb); GenerateModelInterface(table, fb); GenerateModel(table, fb); }); } else { GenerationContext .FileIfPathIsSet(fb => GenerateEntityInterface(table, fb)) .FileIfPathIsSet(fb => GenerateEntity(table, fb)) .FileIfPathIsSet(fb => GenerateModelInterface(table, fb)) .FileIfPathIsSet(fb => GenerateModel(table, fb)); } }); // generate foreign keys and navigation properties. tables.ForEach(table => { GenerateForeignKeys(table); GenerateOneToOnes(table); GenerateHasMany(table); GenerateManyToMany(table); }); }
protected override void GenerateContext() { var contextNamespace = ContextNamespace(); var contextClassName = ContextClassName(); Action <FileBuilder> generateContextInline = (FileBuilder fileBuilder) => { if (!Options.OutputToSingleFile) { var filePath = $"{Options.OutputDir}{Path.DirectorySeparatorChar}{Options.ContextName}.generated.cs"; fileBuilder.Path(filePath); } fileBuilder.Using("Microsoft.EntityFrameworkCore"); fileBuilder.Namespace(contextNamespace, true, ns => { ns.Class(contextClassName, true, contextClass => { contextClass.Partial(true).Inherits(Options.ContextBaseClassName); TablesToGenerate.ForEach(table => { var tableClassFullName = TableClassFullName(table); var tableNamePlural = Pluralize(table.Name); contextClass.Property(tableNamePlural, true, dbSetProp => { dbSetProp.Virtual(true).Type($"DbSet<{tableClassFullName}>"); }); }); // empty constructor. contextClass.Constructor(c => c.Class(contextClass)); // constructor with options. contextClass.Constructor(c => c .Class(contextClass) .Parameter(p => p.Type($"DbContextOptions<{contextClassName}>").Name("options")) .BaseParameter("options") ); // override On Configuring contextClass.Method(m => { m .AccessModifier(AccessModifiers.Protected) .Override(true) .ReturnType("void") .Name("OnConfiguring") .Parameter(p => p.Type("DbContextOptionsBuilder").Name("optionsBuilder")); if (Options.AddConnectionStringOnGenerate) { m.Add(() => { return(IfBuilder.Create() .RawCondition(c => c.Condition("!optionsBuilder.IsConfigured")) .Add(RawLineBuilder.Create( "#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.") .NoEndOfLine()) .Add(UseDatabaseEngineConnectionStringLine())); }); } }); // model creating. contextClass.Method(m => { m .AccessModifier(AccessModifiers.Protected) .Override(true) .ReturnType("void") .Name("OnModelCreating") .Parameter(p => p.Type("ModelBuilder").Name("modelBuilder")); TablesToGenerate.ForEach(table => { AddFluentToMethod(m, table); }); SequenceToGenerate.ForEach(sequence => { var dataType = DataTypeResolver.ResolveType(sequence); var outputType = dataType.GetOutputType(); m.RawLine($"modelBuilder.HasSequence<{outputType}>(\"{sequence.Name}\").StartsAt({sequence.StartAt}).IncrementsBy({sequence.IncrementsBy})"); }); }); }); }); }; if (Options.OutputToSingleFile) { GenerationContext.SingleFile(fb => generateContextInline(fb)); } else { GenerationContext.FileIfPathIsSet(fb => generateContextInline(fb)); } }
protected virtual void AddFluentToMethod(MethodBuilder methodBuilder, ITable table) { var tableNamespace = TableNamespace(table); var tableClassName = TableClassName(table); var tableFullClassName = TableClassFullName(table); var tableClass = GenerationContext.FindClass(tableClassName, tableNamespace); var fluentExpression = MultiLineLambdaExpression.Create() .Parameter(p => p.Name("entity")) .RawLine($"entity.{ToTableFluent(table)}"); //.RawLine($"entity.ToTable(\"{table.Name}\", \"{table.Schema}\")"); var pks = table.Columns.Where(t => t.IsPrimaryKey); var hasCompositeKey = pks.Count() > 1; ; if (hasCompositeKey) { var def = string.Join(", ", pks.Select(pk => { var pkProp = tableClass.FindByMeta <PropertyBuilder>(pk); return($"t.{pkProp.GetName()}"); })); fluentExpression.RawLine($"entity.HasKey(t => new {{ {def} }})"); } else { var pk = pks.First(); var pkProp = tableClass.FindByMeta <PropertyBuilder>(pk); fluentExpression.RawLine($"entity.HasKey(t => t.{pkProp.GetName()})"); } table.Indexes.ForEach(i => { if (!ShouldGenerateIndex(i)) { return; } var line = RawLineBuilder.Create(); string rightExpr; if (i.Columns.Count == 1) { var indexProp = tableClass.FindByMeta <PropertyBuilder>(i.Columns.First()); rightExpr = $"t.{indexProp.GetName()}"; } else { var cols = string.Join(", ", i.Columns.Select(t => $"t.{tableClass.FindByMeta<PropertyBuilder>(t).GetName()}")); rightExpr = $"new {{ {cols} }}"; } line.Append($"entity.HasIndex(t => {rightExpr})"); line.Append($"\n\t.HasName(\"{i.Name}\")"); if (i.IsUnique) { line.Append("\n\t.IsUnique()"); } OnBeforeIndexLineAdded(line, i); fluentExpression.Add(line); }); table.Columns.ForEach(c => { var columnProp = tableClass.FindByMeta <PropertyBuilder>(c); var line = RawLineBuilder.Create(); line.Append($"entity.Property(t => t.{columnProp.GetName()})"); line.Append($".HasColumnType(\"{FluentColumnType(c)}\")"); if (c.IsPrimaryKey) { if (c.IsAutoIncrement) { line.Append(".ValueGeneratedOnAdd()"); } else { line.Append(".ValueGeneratedNever()"); } } else if (!string.IsNullOrWhiteSpace(c.DefaultValue)) { line.Append($".HasDefaultValueSql(\"{c.DefaultValue}\")"); } if (!c.IsNullable) { line.Append(".IsRequired()"); } if (c.CharacterMaximumLength.HasValue && c.CharacterMaximumLength != -1) { line.Append($".HasMaxLength({c.CharacterMaximumLength})"); } if (DataTypeResolver.IsString(c) && !DataTypeResolver.IsUnicode(c)) { line.Append(".IsUnicode(false)"); } fluentExpression.Add(line); }); table.ForeignKeys.ForEach(fk => { if (!TablesToGenerate.Contains(fk.PrimaryKeyColumn.Table)) { return; } var fkProp = tableClass.FindByMeta <PropertyBuilder>(fk); var fkColumnProp = tableClass.FindByMeta <PropertyBuilder>(fk.ForeignKeyColumn); var fkTableNamespace = TableNamespace(fk.PrimaryKeyColumn.Table); var fkTableClassName = TableClassName(fk.PrimaryKeyColumn.Table); var fkTableClass = GenerationContext.FindClass(fkTableClassName, fkTableNamespace); var reverseProp = fkTableClass.FindByMeta <PropertyBuilder>(fk); var line = RawLineBuilder.Create(); line.Append($"entity.HasOne(t => t.{fkProp.GetName()})"); if (!fk.IsOneToOne()) { line.Append($"\n\t.WithMany(t => t.{reverseProp.GetName()})"); line.Append($"\n\t.HasForeignKey(t => t.{fkColumnProp.GetName()})"); } else { line.Append($"\n\t.WithOne(t => t.{reverseProp.GetName()})"); line.Append($"\n\t.HasForeignKey<{tableFullClassName}>(t => t.{fkColumnProp.GetName()})"); } if (IsCascade(fk.DeleteCascadeAction)) { line.Append("\n\t.OnDelete(DeleteBehavior.Delete)"); } else if (IsSetNull(fk.DeleteCascadeAction)) { line.Append("\n\t.OnDelete(DeleteBehavior.SetNull)"); } else { line.Append("\n\t.OnDelete(DeleteBehavior.ClientSetNull)"); } line.Append($"\n\t.HasConstraintName(\"{fk.Name}\")"); line.Comment("Foreign Key"); fluentExpression.Add(line); }); var modelFluentLine = $"modelBuilder.Entity<{tableFullClassName}>({fluentExpression.GenerateInline()})"; methodBuilder.Add(RawLineBuilder.Create(modelFluentLine)); methodBuilder.AddEmptyLine(); }
protected override void GenerateContext() { var fileBuilder = ResolveContextFileBuilder(); var contextNamespace = ContextNamespace(); var contextClassName = ContextClassName(); fileBuilder.Using("System.Linq"); fileBuilder.Namespace(contextNamespace, true, ns => { ns.Class(contextClassName, true, contextClass => { contextClass.Partial(true).Inherits(Options.ContextBaseClassName); TablesToGenerate.ForEach(table => { var tableClassFullName = TableClassFullName(table); var tableNamePlural = Pluralize(table.Name); contextClass.Property(tableNamePlural, true, dbSetProp => { dbSetProp.Type($"System.Data.Entity.DbSet<{tableClassFullName}>"); }); }); contextClass.Constructor(c => c .AccessModifier(AccessModifiers.Omit) .IsStatic(true) .Class(contextClass) .RawLine($"System.Data.Entity.Database.SetInitializer<{Options.ContextName}>(null)") ); contextClass.Constructor(c => c .Class(contextClass) .BaseParameter($"\"{Options.ConnectionStringName ?? Options.ConnectionString}\"") .RawLine("InitializePartial()") ); contextClass.Constructor(c => c .Class(contextClass) .Parameter(p => p.Type("string").Name("connectionString")) .BaseParameter("connectionString") .RawLine("InitializePartial()") ); contextClass.Constructor(c => c .Class(contextClass) .Parameter(p => p.Type("string").Name("connectionString")) .Parameter(p => p.Type("System.Data.Entity.Infrastructure.DbCompiledModel").Name("model")) .BaseParameter("connectionString") .BaseParameter("model") .RawLine("InitializePartial()") ); contextClass.Method(addConfigurationMethod => { addConfigurationMethod .IsStatic(true) .ReturnType("void") .AccessModifier(AccessModifiers.Protected) .Name("AddFluentConfigurations") .Parameter(p => p.Type("System.Data.Entity.DbModelBuilder").Name("modelBuilder")); TablesToGenerate.ForEach(table => { var fcc = TableClassFullName(table) + Options.FluentConfigurationClassSuffix; addConfigurationMethod.RawLine($"modelBuilder.Configurations.Add(new {fcc}())"); }); }); contextClass.Method(m => m .AccessModifier(AccessModifiers.Omit) .Name("OnModelCreatingPartial") .ReturnType("void") .Partial(true) .Parameter(p => p.Type("System.Data.Entity.DbModelBuilder").Name("modelBuilder")) ); contextClass.Method(m => m .AccessModifier(AccessModifiers.Omit) .Name("InitializePartial") .ReturnType("void") .Partial(true) ); contextClass.Method(m => { m .AccessModifier(AccessModifiers.Protected) .Override(true) .ReturnType("void") .Name("OnModelCreating") .Parameter(p => p.Type("System.Data.Entity.DbModelBuilder").Name("modelBuilder")) .RawLine("base.OnModelCreating(modelBuilder)") .RawLine("AddFluentConfigurations(modelBuilder)") .RawLine("OnModelCreatingPartial(modelBuilder)"); }); contextClass.Method(m => { m .AccessModifier(AccessModifiers.Public) .IsStatic(true) .ReturnType("System.Data.Entity.DbModelBuilder") .Name("CreateModel") .Parameter(p => p.Type("System.Data.Entity.DbModelBuilder").Name("modelBuilder")) .Parameter(p => p.Type("string").Name("schema")) .RawLine("AddFluentConfigurations(modelBuilder)") .RawLine("return modelBuilder"); }); }); }); }
// TODO refactor. move to SQL SERVER EF6 /// <summary> /// //method.RawLine($"return Database.SqlQuery<{outputType}>(\"SELECT NEXT VALUE FOR [{sequence.Schema}].[{sequence.Name}];\").First()"); /// </summary> /// <param name="method"></param> /// <param name="outputType"></param> /// <param name="sequence"></param> //protected abstract void GenerateGetNextSequenceLines(MethodBuilder method, string outputType, ISequence sequence); private void GenerateEntityFluentConfiguration(ITable table) { var tableNamespace = TableNamespace(table); var tableFluentConfigurationClassName = $"{TableClassName(table)}{Options.FluentConfigurationClassSuffix}"; var tableClassName = TableClassName(table); var tableClassFullName = TableClassFullName(table); var entityClass = GenerationContext.FindClass(tableClassName, tableNamespace); var contextNamespace = ContextNamespace(); // set the path. var outputDir = Options.ContextOutputDir ?? Options.OutputDir; var fileName = Options.ContextOutputSingleFileName ?? Options.OutputSingleFileName ?? $"{tableFluentConfigurationClassName}.generated.cs"; var path = $"{outputDir}{Path.DirectorySeparatorChar}{fileName}"; GenerationContext.File(path, fileBuilder => { // set the namespace. fileBuilder.Namespace(contextNamespace, true, ns => { ns.Class(tableFluentConfigurationClassName, true, fluentConfigClass => { fluentConfigClass .Partial(true) .Inherits($"System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<{tableClassFullName}>") .Constructor(constructor => { constructor.AddComment("Table mapping & keys"); // to table mapping. constructor.RawLine(ToTableFluent(table)); if (table.Columns.Count(t => t.IsPrimaryKey) > 1) { //HasKey(x => new { x.PurchaseOrderId, x.RequiredDocumentId }); var props = string.Join(", ", table.Columns .Where(t => t.IsPrimaryKey) .OrderBy(t => t.PrimaryKeyOrder) .Select(t => $"x.{entityClass.FindByMeta<PropertyBuilder>(t).GetName()}")); var line = $"HasKey(x => new {{ {props} }})"; constructor.RawLine(line); } else { // pk mapping. var pk = table.Columns.FirstOrDefault(t => t.IsPrimaryKey); var pkProp = entityClass.FindByMeta <PropertyBuilder>(pk); constructor.RawLine($"HasKey(t => t.{pkProp.GetName()})"); } constructor.AddComment("Columns"); // columns mapping. table.Columns.ForEach(column => { var columnProp = entityClass.FindByMeta <PropertyBuilder>(column); var columnLine = RawLineBuilder.Create(); columnLine.Append($"Property(t => t.{columnProp.GetName()})"); columnLine.Append($".HasColumnName(\"{column.Name}\")"); if (column.IsNullable) { columnLine.Append(".IsOptional()"); } else { columnLine.Append(".IsRequired()"); } columnLine.Append($".HasColumnType(\"{column.DataType}\")"); if (column.IsPrimaryKey) { if (IsGenerateOptionIdentity(column)) { columnLine.Append(".HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)"); } else { columnLine.Append(".HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None)"); } /* * // TODO make overridable class method here called IsGenerateOptionIdentity(IColumn) * if (column.IsAutoIncrement) * columnLine.Append(".HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)"); * else if (column.DataType == "uniqueidentifier" && column.DefaultValue.IndexOf("newsequentialid", StringComparison.InvariantCultureIgnoreCase) > -1) * columnLine.Append(".HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)"); * else * columnLine.Append(".HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None)"); */ } if (column.CharacterMaximumLength.HasValue && column.CharacterMaximumLength != -1) { columnLine.Append($".HasMaxLength({column.CharacterMaximumLength})"); } if (DataTypeResolver.IsFixLength(column)) { columnLine.Append(".IsFixedLength()"); } if (DataTypeResolver.IsString(column) && !DataTypeResolver.IsUnicode(column)) { columnLine.Append(".IsUnicode(false)"); } if (column.NumericPrecision.HasValue && column.NumericScale.HasValue && column.NumericScale != 0) { columnLine.Append($".HasPrecision({column.NumericPrecision}, {column.NumericScale})"); } constructor.Add(columnLine); }); constructor.AddComment("Navigations"); table.ForeignKeys.ForEach(fk => { var fkProp = FindNavigation(entityClass, fk); var fkColumnProp = entityClass.FindByMeta <PropertyBuilder>(fk.ForeignKeyColumn); // if null meaning its being filtered. (excluded table from generation) if (fkProp != null) { var line = RawLineBuilder.Create(); var primaryNamespace = TableNamespace(fk.PrimaryKeyColumn.Table); var primaryClassName = TableClassName(fk.PrimaryKeyColumn.Table); var primaryEntity = GenerationContext.FindClass(primaryClassName, primaryNamespace); PropertyBuilder reverseNav; if (fk.PrimaryKeyColumn.Table == fk.ForeignKeyColumn.Table) { reverseNav = FindNavigation(primaryEntity, fk, NavigationKind.HasMany); } else { reverseNav = FindNavigation(primaryEntity, fk); } if (fk.ForeignKeyColumn.IsNullable) { line.Append($"HasOptional(t => t.{fkProp.GetName()})"); } else { line.Append($"HasRequired(t => t.{fkProp.GetName()})"); } if (fk.IsOneToOne()) { line.Append($".WithOptional(t => t.{reverseNav.GetName()})"); } else { line.Append($".WithMany(t => t.{reverseNav.GetName()})"); line.Append($".HasForeignKey(t => t.{fkColumnProp.GetName()})"); } constructor.Add(line); } }); constructor.AddComment("Many to Many"); table.ManyToMany().ToList().ForEach(mtm => { if (mtm.ForeignKeyColumn.PrimaryKeyOrder > 1) { return; } var manyToManyTable = mtm.ForeignKeyColumn.Table; var otherFk = mtm.ForeignKeyColumn.Table.ForeignKeys.First(t => t.ForeignKeyColumn.PrimaryKeyOrder > 1); var otherFkTable = otherFk.PrimaryKeyColumn.Table; var manyProp = FindNavigation(entityClass, mtm); // exclude if not being generated. if (!TablesToGenerate.Contains(otherFk.PrimaryKeyColumn.Table)) { return; } var otherNamespace = TableNamespace(otherFkTable); var otherClassName = TableClassName(otherFkTable); var otherEntity = GenerationContext.FindClass(otherClassName, otherNamespace); var otherProp = FindNavigation(otherEntity, otherFk); var line = RawLineBuilder.Create(); line.Append($"HasMany(t => t.{manyProp.GetName()})"); line.Append($".WithMany(t => t.{otherProp.GetName()})"); line.Append($".Map(t => t.{ToTableFluent(manyToManyTable)}"); line.Append($".MapLeftKey(\"{mtm.ForeignKeyColumn.Name}\")"); line.Append($".MapRightKey(\"{otherFk.ForeignKeyColumn.Name}\"))"); constructor.Add(line); }); }); }); }); }); }