private string GetFkName(IReadOnlyList <Column> fromColumns)
        {
            var sb = new StringBuilder();

            foreach (var fromCol in fromColumns)
            {
                sb.Append(Inf.Pascalise(Inf.Singularise(RemoveSuffix(fromCol.Name))));
            }
            return(sb.ToString());
        }
        private void WriteEntityFiles()
        {
            using (BeginFile($"{options.ContextName ?? Inf.Pascalise(Db.Name)}Entities.cs", options.OneFilePerEntity == false))
                using (WriteHeader(options.OneFilePerEntity == false))
                    foreach (var table in Db.Schemas.SelectMany(s => s.Tables).OrderBy(t => t.Name))
                    {
                        var className = Inf.Pascalise(Inf.Singularise(table.Name));
                        table.Metadata["Class"] = className;

                        using (BeginFile($"{className}.cs", options.OneFilePerEntity))
                            using (WriteHeader(options.OneFilePerEntity))
                            {
                                WriteEntity(table);
                            }
                    }
        }
        private void WriteEntity(Table table)
        {
            var existingNames   = new HashSet <string>();
            var className       = table.Metadata["Class"];
            var classInterfaces = "";
            int i = 1;

            existingNames.Add(className);

            W($"[GeneratedCode(\"Geco\", \"{Assembly.GetEntryAssembly().GetName().Version}\")]", options.GeneratedCodeAttribute);
            W($"public partial class {className}{(!String.IsNullOrWhiteSpace(classInterfaces) ? ": " + classInterfaces : "")}");
            WI("{");
            {
                var keyProperties = table.Columns.Where <Column>(c => c.IsKey);
                if (keyProperties.Any())
                {
                    W("// Key Properties", options.GenerateComments);
                    foreach (var column in keyProperties)
                    {
                        var propertyName = Inf.Pascalise(column.Name);
                        CheckClash(ref propertyName, existingNames, ref i);
                        column.Metadata["Property"] = propertyName;
                        W($"public {GetClrTypeName(column.DataType)}{GetNullable(column)} {propertyName} {{ get; set; }}");
                    }
                    W();
                }


                var scalarProperties = table.Columns.Where <Column>(c => !c.IsKey);
                if (scalarProperties.Any())
                {
                    W("// Scalar Properties", options.GenerateComments);
                    foreach (var column in scalarProperties)
                    {
                        var propertyName = Inf.Pascalise(column.Name);
                        CheckClash(ref propertyName, existingNames, ref i);
                        column.Metadata["Property"] = propertyName;
                        W($"public {GetClrTypeName(column.DataType)}{GetNullable(column)} {propertyName} {{ get; set; }}");
                    }
                    W();
                }

                if (table.ForeignKeys.Any())
                {
                    W("// Foreign keys", options.GenerateComments);
                    foreach (var fk in table.ForeignKeys.OrderBy(t => t.ParentTable.Name).ThenBy(t => t.FromColumns[0].Name))
                    {
                        var targetClassName = Inf.Pascalise(Inf.Singularise(fk.TargetTable.Name));
                        //var propertyName = Inf.Pascalise(Inf.Singularise(RemoveSuffix(column.Name)));

                        string propertyName;
                        if (table.ForeignKeys.Count(f => f.TargetTable == fk.TargetTable) > 1)
                        {
                            propertyName = Inf.Pluralise(targetClassName) + GetFkName(fk.ToColumns);
                        }
                        else
                        {
                            propertyName = Inf.Pluralise(targetClassName);
                        }

                        if (CheckClash(ref propertyName, existingNames, ref i))
                        {
                            propertyName = Inf.Pascalise(Inf.Pluralise(fk.TargetTable.Name)) + GetFkName(fk.FromColumns);
                            CheckClash(ref propertyName, existingNames, ref i);
                        }

                        fk.Metadata["NavProperty"] = propertyName;
                        foreach (var column in fk.FromColumns)
                        {
                            column.Metadata["NavProperty"] = propertyName;
                        }
                        W("[JsonIgnore]", options.JsonSerialization);
                        W($"public {targetClassName} {propertyName} {{ get; set; }}");
                    }
                    W();
                }

                if (table.IncomingForeignKeys.Any())
                {
                    W("// Reverse navigation", options.GenerateComments);
                    foreach (var fk in table.IncomingForeignKeys.OrderBy(t => t.ParentTable.Name).ThenBy(t => t.FromColumns[0].Name))
                    {
                        var    targetClassName = Inf.Pascalise(Inf.Singularise(fk.ParentTable.Name));
                        string propertyName;
                        if (table.IncomingForeignKeys.Count(f => f.ParentTable == fk.ParentTable) > 1)
                        {
                            propertyName = Inf.Pluralise(targetClassName) + GetFkName(fk.FromColumns);
                        }
                        else
                        {
                            propertyName = Inf.Pluralise(targetClassName);
                        }

                        if (CheckClash(ref propertyName, existingNames, ref i))
                        {
                            propertyName = Inf.Pascalise(Inf.Pluralise(fk.ParentTable.Name)) + GetFkName(fk.FromColumns);
                            CheckClash(ref propertyName, existingNames, ref i);
                        }
                        fk.Metadata["Property"] = propertyName;
                        fk.Metadata["Type"]     = targetClassName;
                        W("[JsonIgnore]", options.JsonSerialization);
                        W($"public List<{targetClassName}> {propertyName} {{ get; set; }}");
                    }
                    W();

                    W($"public {className}()");
                    WI("{");
                    {
                        foreach (var fk in table.IncomingForeignKeys.OrderBy <ForeignKey, string>(t => t.ParentTable.Name).ThenBy(t => t.FromColumns[0].Name))
                        {
                            W($"this.{fk.Metadata["Property"]} = new List<{fk.Metadata["Type"]}>();");
                        }
                    }
                    DW("}");
                }
            }
            DW("}");
            W("", !options.OneFilePerEntity);
        }