Esempio n. 1
0
        static void Main(string[] args)
        {
            string         projectFolder = System.IO.Path.Combine(CodegenCS.Utils.IO.GetCurrentDirectory().FullName, @"..\AdventureWorks.Business");
            CodegenContext context       = new CodegenContext(outputFolder: projectFolder + "\\GeneratedCode");
            Generator      generator     = new Generator(
                context: context,
                createConnection: () => new System.Data.SqlClient.SqlConnection(@"
                    Data Source=LENOVOFLEX5\SQLEXPRESS;
                    Initial Catalog=AdventureWorks;
                    Integrated Security=True;
                    Application Name=EntityFramework POCO Generator"
                                                                                ),
                targetFrameworkVersion: 4.72m
                );

            generator.GenerateMultipleFiles(); // generates in memory

            // since no errors, first modify csproj, then we save all files

            // Generate all files and add each into to the csproj
            MSBuildProjectEditor editor = new MSBuildProjectEditor(projectFilePath: projectFolder + @"\AdventureWorks.Business.csproj");

            //string templateFile = Path.Combine(CodegenCS.Utils.IO.GetCurrentDirectory().FullName);
            foreach (var o in context.OutputFilesAbsolute)
            {
                editor.AddItem(itemPath: o.Key, itemType: o.Value.ItemType);
            }
            editor.Save();
            context.SaveFiles(deleteOtherFiles: true);
        }
    /// <summary>
    /// Generates POCOS
    /// </summary>
    /// <param name="targetFolder">Absolute path of the target folder where files will be written</param>
    public void Generate(string targetFolder)
    {
        Console.WriteLine($"TargetFolder: {targetFolder}");

        _generatorContext = new CodegenContext(outputFolder: targetFolder);

        Console.WriteLine("Reading Schema...");

        DatabaseSchema schema = Newtonsoft.Json.JsonConvert.DeserializeObject <DatabaseSchema>(File.ReadAllText(_inputJsonSchema));

        foreach (var table in schema.Tables)
        {
            string entityClassName = GetClassNameForTable(table);

            var schemaAndtable = new Tuple <string, string>(table.TableSchema, table.TableName);
            if (!_usedIdentifiers.ContainsKey(schemaAndtable))
            {
                _usedIdentifiers.Add(schemaAndtable, new List <string>()
                {
                    entityClassName
                });
            }

            string tableFilePath = GetFileNameForTable(table);
            Console.WriteLine($"Generating {tableFilePath}...");
            using (var writer = _generatorContext.GetOutputFile(relativePath: tableFilePath).Writer)
            {
                writer.WriteLine(@"using System;");
                writer.WriteLine(@"using System.Collections.Generic;");
                writer.WriteLine();
                using (writer.WithCBlock($"namespace {Namespace}"))
                {
                    using (writer.WithCBlock($"public partial class {entityClassName}"))
                    {
                        var columns = table.Columns.Where(c => ShouldProcessColumn(table, c));
                        foreach (var column in columns)
                        {
                            string propertyName = GetPropertyNameForDatabaseColumn(table, column, _usedIdentifiers[schemaAndtable]);
                            writer.WriteLine($"public {GetTypeDefinitionForDatabaseColumn(table, column) ?? ""} {propertyName} {{ get; set; }}");
                        }
                    }
                }
            }
        }

        // since no errors happened, let's save all files
        _generatorContext.SaveFiles();

        Console.WriteLine("Success!");
    }
Esempio n. 3
0
    /// <summary>
    /// Generates POCOS
    /// </summary>
    /// <param name="targetFolder">Absolute path of the target folder where files will be written</param>
    public void Generate(string targetFolder)
    {
        Console.WriteLine($"TargetFolder: {targetFolder}");

        _generatorContext = new CodegenContext();

        Console.WriteLine("Reading Schema...");

        LogicalSchema schema = Newtonsoft.Json.JsonConvert.DeserializeObject <LogicalSchema>(File.ReadAllText(_inputJsonSchema));
        //schema.Tables = schema.Tables.Select(t => Map<LogicalTable, Table>(t)).ToList<Table>();

        CodegenOutputFile writer = null;

        if (SingleFile)
        {
            writer = _generatorContext[singleFileName];
            writer
            .WriteLine(@"using System;")
            .WriteLine(@"using System.Collections.Generic;")
            .WriteLine(@"using System.ComponentModel.DataAnnotations;")
            .WriteLine(@"using System.ComponentModel.DataAnnotations.Schema;")
            .WriteLine(@"using System.Linq;");
            if (GenerateActiveRecord)
            {
                writer.WriteLine(@"using Dapper;");
            }
            writer
            .WriteLine()
            .WriteLine($"namespace {Namespace}").WriteLine("{").IncreaseIndent();
        }

        if (GenerateActiveRecord)
        {
            using (var writerConnectionFactory = _generatorContext["..\\IDbConnectionFactory.cs"])
            {
                writerConnectionFactory.WriteLine($@"
                    using System;
                    using System.Data;
                    using System.Data.SqlClient;

                    namespace {Namespace}
                    {{
                        public class IDbConnectionFactory
                        {{
                            public static IDbConnection CreateConnection()
                            {{
                                string connectionString = @""Data Source=MYWORKSTATION\\SQLEXPRESS;
                                                Initial Catalog=AdventureWorks;
                                                Integrated Security=True;"";

                                return new SqlConnection(connectionString);
                            }}
                        }}
                    }}
                ");
            }
        }

        foreach (var table in schema.Tables.OrderBy(t => GetClassNameForTable(t)))
        {
            if (table.TableType == "VIEW")
            {
                continue;
            }

            GeneratePOCO(table);
        }

        if (SingleFile)
        {
            writer.DecreaseIndent().WriteLine("}"); // end of namespace
        }
        // since no errors happened, let's save all files
        _generatorContext.SaveFiles(outputFolder: targetFolder);

        Console.WriteLine("Success!");
    }
Esempio n. 4
0
    /// <summary>
    /// Generates POCOS
    /// </summary>
    public void Generate()
    {
        while (string.IsNullOrEmpty(InputJsonSchema))
        {
            Console.WriteLine($"[Choose an Input JSON Schema File]");
            Console.Write($"Input file: ");
            InputJsonSchema = Console.ReadLine();
        }

        while (string.IsNullOrEmpty(TargetFolder))
        {
            Console.WriteLine($"[Choose a Target Folder]");
            Console.Write($"Target Folder: ");
            TargetFolder = Console.ReadLine();
        }

        while (string.IsNullOrEmpty(Namespace))
        {
            Console.WriteLine($"[Choose a Namespace]");
            Console.Write($"Namespace: ");
            Namespace = Console.ReadLine();
        }


        _generatorContext = new CodegenContext();

        Console.WriteLine("Reading Schema...");

        LogicalSchema schema = Newtonsoft.Json.JsonConvert.DeserializeObject <LogicalSchema>(File.ReadAllText(InputJsonSchema));
        //schema.Tables = schema.Tables.Select(t => Map<LogicalTable, Table>(t)).ToList<Table>();

        CodegenOutputFile writer = null;

        if (SingleFile)
        {
            writer = _generatorContext[singleFileName];
            writer
            .WriteLine(@"using System;")
            .WriteLine(@"using System.Collections.Generic;")
            .WriteLine(@"using System.ComponentModel.DataAnnotations;")
            .WriteLine(@"using System.ComponentModel.DataAnnotations.Schema;")
            .WriteLine(@"using System.Linq;");
            if (GenerateActiveRecord)
            {
                writer.WriteLine(@"using Dapper;");
            }
            if (TrackPropertiesChange)
            {
                writer.WriteLine(@"using System.ComponentModel;");
            }
            writer
            .WriteLine()
            .WriteLine($"namespace {Namespace}").WriteLine("{").IncreaseIndent();
        }

        if (GenerateCrudExtensions)
        {
            _dbConnectionCrudExtensions = _generatorContext[CrudExtensionsFile];
            _dbConnectionCrudExtensions.Write(@"
                using Dapper;
                using System;
                using System.Collections.Generic;
                using System.Data;
                using System.Linq;
                using System.Runtime.CompilerServices;
                ");
            _dbConnectionCrudExtensions
            .WriteLine()
            .WriteLine($"namespace {Namespace}").WriteLine("{").IncreaseIndent()
            .WriteLine($"public static class {CrudExtensionsClass}").WriteLine("{").IncreaseIndent();
        }

        if (GenerateActiveRecord)
        {
            using (var writerConnectionFactory = _generatorContext[ActiveRecordIDbConnectionFactoryFile])
            {
                writerConnectionFactory.WriteLine($@"
                    using System;
                    using System.Data;
                    using System.Data.SqlClient;

                    namespace {Namespace}
                    {{
                        public class IDbConnectionFactory
                        {{
                            public static IDbConnection CreateConnection()
                            {{
                                string connectionString = @""Data Source=MYWORKSTATION\\SQLEXPRESS;
                                                Initial Catalog=AdventureWorks;
                                                Integrated Security=True;"";

                                return new SqlConnection(connectionString);
                            }}
                        }}
                    }}
                ");
            }
        }

        foreach (var table in schema.Tables.OrderBy(t => GetClassNameForTable(t)))
        {
            if (!ShouldProcessTable(table))
            {
                continue;
            }

            GeneratePOCO(table);
        }

        if (GenerateCrudExtensions)
        {
            _dbConnectionCrudExtensions
            .DecreaseIndent().WriteLine("}")         // end of class
            .DecreaseIndent().WriteLine("}");        // end of namespace
        }
        if (SingleFile)
        {
            writer.DecreaseIndent().WriteLine("}");     // end of namespace
        }
        // since no errors happened, let's save all files
        _generatorContext.SaveFiles(outputFolder: TargetFolder);

        Console.WriteLine("Success!");
    }
Esempio n. 5
0
    /// <summary>
    /// Generates Entities and DbContext
    /// </summary>
    public void Generate()
    {
        while (string.IsNullOrEmpty(InputJsonSchema))
        {
            Console.WriteLine($"[Choose an Input JSON Schema File]");
            Console.Write($"Input file: ");
            InputJsonSchema = Console.ReadLine();
        }

        while (string.IsNullOrEmpty(TargetFolder))
        {
            Console.WriteLine($"[Choose a Target Folder]");
            Console.Write($"Target Folder: ");
            TargetFolder = Console.ReadLine();
        }

        while (string.IsNullOrEmpty(Namespace))
        {
            Console.WriteLine($"[Choose a Namespace]");
            Console.Write($"Namespace: ");
            Namespace = Console.ReadLine();
        }

        while (string.IsNullOrEmpty(ContextName))
        {
            Console.WriteLine($"[Choose a DbContext Name]");
            Console.Write($"DbContext Name: ");
            ContextName = Console.ReadLine();
        }


        _generatorContext = new CodegenContext();

        Console.WriteLine("Reading Schema...");

        LogicalSchema schema = Newtonsoft.Json.JsonConvert.DeserializeObject <LogicalSchema>(File.ReadAllText(InputJsonSchema));

        //schema.Tables = schema.Tables.Select(t => Map<LogicalTable, Table>(t)).ToList<Table>();

        // Define a unique property name for each column
        foreach (var table in schema.Tables)
        {
            if (!ShouldProcessTable(table))
            {
                continue;
            }
            var columns = table.Columns.Where(c => ShouldProcessColumn(table, c));
            foreach (var column in columns)
            {
                string propertyName = GetPropertyNameForDatabaseColumn(table, column);
            }
        }

        // Define a unique property name for each navigation property and reverse navigation property
        foreach (var table in schema.Tables)
        {
            foreach (var fk in table.ForeignKeys.ToList())
            {
                var fkTable = table;
                var pkTable = schema.Tables.SingleOrDefault(t => t.TableSchema == fk.PKTableSchema && t.TableName == fk.PKTableName);
                if (pkTable == null)
                {
                    Console.WriteLine($"Can't find table {fk.PKTableName}");
                    continue;
                }
                var reverseFk = pkTable.ChildForeignKeys.Single(rfk => rfk.ForeignKeyConstraintName == fk.ForeignKeyConstraintName);

                SetForeignKeyPropertyNames(pkTable, fkTable, fk, reverseFk);
            }
        }

        #region foreach (var table in schema.Tables)
        foreach (var table in schema.Tables)
        {
            if (!ShouldProcessTable(table))
            {
                continue;
            }
            string entityClassName = GetClassNameForTable(table);

            string tableFilePath = GetFileNameForTable(table);
            Console.WriteLine($"Generating {tableFilePath}...");
            using (var writer = _generatorContext[tableFilePath])
            {
                writer.WriteLine(@"using System;");
                writer.WriteLine(@"using System.Collections.Generic;");
                if (withAttributes)
                {
                    writer.WriteLine(@"using System.ComponentModel.DataAnnotations;");
                    writer.WriteLine(@"using System.ComponentModel.DataAnnotations.Schema;");
                }
                writer.WriteLine();
                using (writer.WithCBlock($"namespace {Namespace}"))
                {
                    if (withAttributes && table.TableSchema != "dbo")     //TODO or table different than class name?
                    {
                        writer.WriteLine($"[Table(\"{table.TableName}\", Schema = \"{table.TableSchema}\")]");
                    }
                    else if (entityClassName.ToLower() != table.TableName.ToLower())
                    {
                        writer.WriteLine($"[Table(\"{table.TableName}\")]");
                    }
                    using (writer.WithCBlock($"public partial class {entityClassName}"))
                    {
                        if (table.ChildForeignKeys.Any())
                        {
                            using (writer.WithCBlock($"public {entityClassName}()"))
                            {
                                foreach (var fk in table.ChildForeignKeys.OrderBy(fk => fk.NavigationPropertyName))
                                {
                                    var fkTable = schema.Tables.Single(t => t.TableSchema == fk.FKTableSchema && t.TableName == fk.FKTableName);
                                    writer.WriteLine($"{fk.NavigationPropertyName} = new HashSet<{GetClassNameForTable(fkTable)}>();");
                                }
                            }
                            writer.WriteLine();
                        }

                        var columns = table.Columns.Where(c => ShouldProcessColumn(table, c));
                        foreach (var column in columns)
                        {
                            string propertyName = GetPropertyNameForDatabaseColumn(table, column);
                            string clrType      = GetTypeDefinitionForDatabaseColumn(table, column) ?? "";
                            if (withAttributes)
                            {
                                if (column.IsPrimaryKeyMember)
                                {
                                    writer.WriteLine("[Key]");
                                }
                                if (!column.IsNullable && clrType == "System.String" && !column.IsPrimaryKeyMember)     // reference types are always nullable (no need "?"), so must specify this.
                                {
                                    writer.WriteLine($"[Required]");
                                }

                                string typeName = null;     // TODO: combine with identical block
                                if (column.SqlDataType == "datetime" || column.SqlDataType == "smallmoney" || column.SqlDataType == "money" || column.SqlDataType == "xml")
                                {
                                    typeName = column.SqlDataType;
                                }
                                else if (column.SqlDataType == "decimal")
                                {
                                    typeName = $"decimal({column.NumericPrecision}, {column.NumericScale})";
                                }

                                if (column.ColumnName != propertyName && typeName != null)
                                {
                                    writer.WriteLine($"[Column(\"{column.ColumnName}\", TypeName = \"{typeName}\")]");
                                }
                                else if (column.ColumnName != propertyName && typeName == null)
                                {
                                    writer.WriteLine($"[Column(\"{column.ColumnName}\")]");
                                }
                                else if (column.ColumnName == propertyName && typeName != null)
                                {
                                    writer.WriteLine($"[Column(TypeName = \"{typeName}\")]");
                                }

                                if (clrType == "System.String" && column.MaxLength != -1)
                                {
                                    writer.WriteLine($"[StringLength({column.MaxLength})]");
                                }
                            }

                            writer.WriteLine($"public {clrType} {propertyName} {{ get; set; }}");
                        }

                        if (table.ForeignKeys.Any() || table.ChildForeignKeys.Any())
                        {
                            writer.WriteLine();
                        }
                        foreach (var childToParentFK in table.ForeignKeys.OrderBy(fk => fk.NavigationPropertyName))
                        {
                            var fkTable         = table;
                            var pkTable         = schema.Tables.Single(t => t.TableSchema == childToParentFK.PKTableSchema && t.TableName == childToParentFK.PKTableName);
                            var parentToChildFK = pkTable.ChildForeignKeys.Single(fk => fk.ForeignKeyConstraintName == childToParentFK.ForeignKeyConstraintName);

                            var fkCol = childToParentFK.Columns.First().FKColumnName;     //TODO: composite keys
                            Console.WriteLine($"{table.TableName}{fkCol}");
                            if (withAttributes)
                            {
                                writer.WriteLine($"[ForeignKey(nameof({table.ColumnPropertyNames[fkCol]}))]");
                                writer.WriteLine($"[InverseProperty(nameof({GetClassNameForTable(pkTable)}.{parentToChildFK.NavigationPropertyName}))]");
                            }
                            writer.WriteLine($"public virtual {GetClassNameForTable(pkTable)} {childToParentFK.NavigationPropertyName} {{ get; set; }}");
                        }
                        foreach (var parentToChildFK in table.ChildForeignKeys.OrderBy(fk => fk.NavigationPropertyName))
                        {
                            var pkTable         = table;
                            var fkTable         = schema.Tables.Single(t => t.TableSchema == parentToChildFK.FKTableSchema && t.TableName == parentToChildFK.FKTableName);
                            var childToParentFK = fkTable.ForeignKeys.Single(fk => fk.ForeignKeyConstraintName == parentToChildFK.ForeignKeyConstraintName);
                            var fkCol           = parentToChildFK.Columns.First().FKColumnName; //TODO: composite keys
                            if (withAttributes)
                            {
                                //writer.WriteLine($"[InverseProperty(nameof({GetClassNameForTable(fkTable)}.{fk.ReverseNavigationPropertyName}))]"); // some cases attribute is set by nameof?
                                writer.WriteLine($"[InverseProperty(\"{childToParentFK.NavigationPropertyName}\")]");     // some cases attribute is set by nameof?
                            }
                            writer.WriteLine($"public virtual ICollection<{GetClassNameForTable(fkTable)}> {parentToChildFK.NavigationPropertyName} {{ get; set; }} ");
                        }
                    }
                }
            }
        }
        #endregion

        #region DbContext
        using (var dbContextWriter = _generatorContext[ContextName + ".cs"])
        {
            dbContextWriter.WriteLine("using System;");
            dbContextWriter.WriteLine("using Microsoft.EntityFrameworkCore;");
            dbContextWriter.WriteLine("using Microsoft.EntityFrameworkCore.Metadata;");
            dbContextWriter.WriteLine("");
            using (dbContextWriter.WithCBlock($"namespace {Namespace}"))
            {
                using (dbContextWriter.WithCBlock($"public partial class {ContextName} : DbContext"))
                {
                    using (dbContextWriter.WithCBlock($"public {ContextName}()"))
                    {
                    }
                    dbContextWriter.WriteLine();

                    using (dbContextWriter.WithCBlock($"public {ContextName}(DbContextOptions<{ContextName}> options){Environment.NewLine}    : base(options)"))
                    {
                    }
                    dbContextWriter.WriteLine();

                    foreach (var table in schema.Tables.OrderBy(t => GetClassNameForTable(t)))
                    {
                        if (!ShouldProcessTable(table))
                        {
                            continue;
                        }
                        string entityClassName = GetClassNameForTable(table);

                        dbContextWriter.WriteLine($"public virtual DbSet<{entityClassName}> {entityClassName} {{ get; set; }}");
                    }

                    dbContextWriter.WriteLine();
                    dbContextWriter.WriteLine();
                    dbContextWriter.WriteLine();
                    using (dbContextWriter.WithCBlock($"protected override void OnModelCreating(ModelBuilder modelBuilder)"))
                    {
                        foreach (var table in schema.Tables.OrderBy(t => GetClassNameForTable(t)))
                        {
                            if (!ShouldProcessTable(table))
                            {
                                continue;
                            }
                            string entityClassName = GetClassNameForTable(table);
                            using (dbContextWriter.WithIndent($"modelBuilder.Entity<{GetClassNameForTable(table)}>(entity =>{Environment.NewLine}{{{Environment.NewLine}", $"{Environment.NewLine}}});{Environment.NewLine}{Environment.NewLine}"))
                            {
                                var pkCols = table.Columns.Where(c => c.IsPrimaryKeyMember);
                                if (pkCols.Any() && !string.IsNullOrEmpty(table.PrimaryKeyName))
                                {
                                    if (pkCols.Count() == 1)
                                    {
                                        dbContextWriter.Write($"entity.HasKey(e => e.{GetPropertyNameForDatabaseColumn(table, pkCols.Single())})");
                                    }
                                    else
                                    {
                                        dbContextWriter.Write($"entity.HasKey(e => new {{ " +
                                                              string.Join(", ", pkCols.Select(pk => $"e.{GetPropertyNameForDatabaseColumn(table, pk)}")) +
                                                              $"}})");
                                    }

                                    List <string> commands = new List <string>();
                                    dbContextWriter.Write($"{Environment.NewLine}    .HasName(\"{table.PrimaryKeyName}\")");
                                    //commands.Add($"    .HasName(\"{table.PrimaryKeyName}\");");
                                    if (!table.PrimaryKeyIsClustered)
                                    {
                                        dbContextWriter.Write($"{Environment.NewLine}    .IsClustered(false)");
                                    }
                                    //commands.Add($"    .IsClustered(false);");
                                    //Extensions.WriteChainedMethods(dbContextWriter, commands); // dbContextWriter.WriteChainedMethods(commands); - CSX doesn't allow extensions
                                    dbContextWriter.WriteLine($";{Environment.NewLine}");
                                }
                                else
                                {
                                    dbContextWriter.WriteLine($"entity.HasNoKey();{Environment.NewLine}");
                                }

                                if (!withAttributes)
                                {
                                    dbContextWriter.WriteLine($"entity.ToTable(\"{table.TableName}\", \"{table.TableSchema}\");{Environment.NewLine}");
                                }

                                if (!string.IsNullOrEmpty(table.TableDescription))
                                {
                                    dbContextWriter.WriteLine($"entity.HasComment(\"{table.TableDescription.Replace("\"", "\\\"")}\");");
                                    dbContextWriter.WriteLine();
                                }

                                dbContextWriter.Write($"{null}");

                                foreach (var index in table.Indexes
                                         .Where(i => i.PhysicalType == "CLUSTERED" || i.PhysicalType == "NONCLUSTERED")
                                         .Where(i => i.LogicalType != "PRIMARY_KEY")
                                         .Where(i => i.Columns.Any())
                                         .OrderBy(i => GetPropertyNameForDatabaseColumn(table, i.Columns.First().ColumnName))
                                         )
                                {
                                    dbContextWriter.Write($"entity.HasIndex(e => e.{GetPropertyNameForDatabaseColumn(table, index.Columns.First().ColumnName)})");
                                    dbContextWriter.Write($"{Environment.NewLine}    .HasName(\"{index.IndexName}\")");
                                    if (index.LogicalType == "UNIQUE_INDEX" || index.LogicalType == "UNIQUE_CONSTRAINT")
                                    {
                                        dbContextWriter.Write($"{Environment.NewLine}    .IsUnique()");
                                    }
                                    dbContextWriter.WriteLine($";{Environment.NewLine}");
                                }

                                foreach (var column in table.Columns
                                         .OrderBy(c => c.IsPrimaryKeyMember ? 0 : 1)
                                         .ThenBy(c => c.IsPrimaryKeyMember ? c.OrdinalPosition : 0) // respect PK order...
                                         .ThenBy(c => GetPropertyNameForDatabaseColumn(table, c))   // but for other columns do alphabetically
                                         )
                                {
                                    dbContextWriter.Write($"entity.Property(e => e.{GetPropertyNameForDatabaseColumn(table, column)})");
                                    if (!withAttributes && column.ColumnName != GetPropertyNameForDatabaseColumn(table, column))
                                    {
                                        dbContextWriter.Write($"{Environment.NewLine}    .HasColumnName(\"{column.ColumnName}\")");
                                    }

                                    string typeName = null;     // TODO: combine with identical block
                                    if (column.SqlDataType == "datetime" || column.SqlDataType == "smallmoney" || column.SqlDataType == "money" || column.SqlDataType == "xml")
                                    {
                                        typeName = column.SqlDataType;
                                    }
                                    else if (column.SqlDataType == "decimal")
                                    {
                                        typeName = $"decimal({column.NumericPrecision}, {column.NumericScale})";
                                    }
                                    if (typeName != null)
                                    {
                                        dbContextWriter.Write($"{Environment.NewLine}    .HasColumnType(\"{typeName}\")");
                                    }

                                    string defaultSetting = column.DefaultSetting;
                                    if (!string.IsNullOrEmpty(defaultSetting))
                                    {
                                        try
                                        {
                                            Type clrType = Type.GetType(column.ClrType);
                                            if ((clrType == typeof(int) ||
                                                 clrType == typeof(decimal) ||
                                                 clrType == typeof(byte) ||
                                                 clrType == typeof(float) ||
                                                 clrType == typeof(long) ||
                                                 clrType == typeof(double) ||
                                                 clrType == typeof(short) ||
                                                 clrType == typeof(uint) ||
                                                 clrType == typeof(ulong)
                                                 ) && !column.IsNullable && defaultSetting == "((0))")
                                            {
                                                defaultSetting = null;
                                            }
                                            //TODO: object def = GetDefault(clrType);
                                        }
                                        catch (Exception ex)
                                        {
                                        }
                                    }
                                    if (defaultSetting != null)     //TODO: non-nullable numerics will have default 0, so ((0)) can be ignored. etc.
                                    {
                                        dbContextWriter.Write($"{Environment.NewLine}    .HasDefaultValueSql(\"{defaultSetting}\")");
                                    }

                                    if (!column.IsNullable && column.ClrType == "System.String" && !column.IsPrimaryKeyMember)     // reference types are always nullable (no need "?"), so must specify this.
                                    {
                                        dbContextWriter.Write($"{Environment.NewLine}    .IsRequired()");
                                    }
                                    if (column.ClrType == "System.String" && column.MaxLength != -1)
                                    {
                                        dbContextWriter.Write($"{Environment.NewLine}    .HasMaxLength({column.MaxLength})");
                                    }
                                    if (column.SqlDataType == "char" || column.SqlDataType == "nchar")
                                    {
                                        dbContextWriter.Write($"{Environment.NewLine}    .IsFixedLength()");
                                    }

                                    if (!string.IsNullOrEmpty(column.ColumnDescription))
                                    {
                                        dbContextWriter.Write($"{Environment.NewLine}    .HasComment(\"{column.ColumnDescription.Replace("\"", "\\\"")}\")");
                                    }
                                    dbContextWriter.WriteLine($";{Environment.NewLine}");

                                    /*
                                     * bool hasLineBreaks = false;
                                     *
                                     * if (!string.IsNullOrEmpty(c.DefaultSetting))
                                     * {
                                     *  if (!hasLineBreaks) { dbContextWriter.IncreaseIndent(); hasLineBreaks = true; }
                                     *  dbContextWriter.WriteLine($"{Environment.NewLine}.HasDefaultValueSql(\"{c.DefaultSetting}\")");
                                     * }
                                     * if (c.SqlDataType == "char" || c.SqlDataType == "nchar")
                                     * {
                                     *  if (!hasLineBreaks) { dbContextWriter.IncreaseIndent(); hasLineBreaks = true; }
                                     *  dbContextWriter.WriteLine($"{Environment.NewLine}.IsFixedLength()");
                                     * }
                                     *
                                     * if (!string.IsNullOrEmpty(c.ColumnDescription))
                                     *  dbContextWriter.WriteLine($".HasComment(\"{c.ColumnDescription.Replace("\"", "\\\"")}\");");
                                     *
                                     * if (hasLineBreaks)
                                     *  dbContextWriter.DecreaseIndent();
                                     * dbContextWriter.WriteLine();
                                     */
                                }
                                foreach (var childToParentFK in table.ForeignKeys
                                         .OrderBy(fk => fk.NavigationPropertyName)
                                         )
                                {
                                    var fkTable         = table;
                                    var pkTable         = schema.Tables.Single(t => t.TableSchema == childToParentFK.PKTableSchema && t.TableName == childToParentFK.PKTableName);
                                    var parentToChildFK = pkTable.ChildForeignKeys.Single(fk => fk.ForeignKeyConstraintName == childToParentFK.ForeignKeyConstraintName);

                                    var fkCol = fkTable.Columns.Single(c => c.ColumnName == childToParentFK.Columns.First().FKColumnName);     //TODO: composite keys

                                    dbContextWriter.Write($"{Environment.NewLine}entity.HasOne(d => d.{childToParentFK.NavigationPropertyName})");
                                    using (dbContextWriter.WithIndent())
                                    {
                                        dbContextWriter.Write($"{Environment.NewLine}.WithMany(p => p.{parentToChildFK.NavigationPropertyName})");
                                        dbContextWriter.Write($"{Environment.NewLine}.HasForeignKey(d => d.{GetPropertyNameForDatabaseColumn(fkTable, fkCol)})");

                                        // NO_ACTION seems like a bug in ef dbcontext scaffold when we use -d (annotations) ?
                                        if (parentToChildFK.OnDeleteCascade == "SET_NULL" || (withAttributes && parentToChildFK.OnDeleteCascade == "NO_ACTION"))
                                        {
                                            dbContextWriter.Write($"{Environment.NewLine}.OnDelete(DeleteBehavior.ClientSetNull)");
                                        }

                                        dbContextWriter.WriteLine($";");
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        #endregion

        // since no errors happened, let's save all files
        _generatorContext.SaveFiles(outputFolder: TargetFolder);

        Console.WriteLine("Success!");
    }