diff --git a/EntityFramework Reverse POCO Generator/EntityFramework Reverse POCO Generator.csproj b/EntityFramework Reverse POCO Generator/EntityFramework Reverse POCO Generator.csproj index b5bc3ed7..bf859b56 100644 --- a/EntityFramework Reverse POCO Generator/EntityFramework Reverse POCO Generator.csproj +++ b/EntityFramework Reverse POCO Generator/EntityFramework Reverse POCO Generator.csproj @@ -24,6 +24,7 @@ false false true + @@ -36,7 +37,7 @@ Properties EntityFramework_Reverse_POCO_Generator EntityFramework Reverse POCO Generator - v4.5 + v4.8 false false false diff --git a/EntityFramework.Reverse.POCO.Generator/EF.Reverse.POCO.v3.ttinclude b/EntityFramework.Reverse.POCO.Generator/EF.Reverse.POCO.v3.ttinclude index b5eb4b62..32c01bdb 100644 --- a/EntityFramework.Reverse.POCO.Generator/EF.Reverse.POCO.v3.ttinclude +++ b/EntityFramework.Reverse.POCO.Generator/EF.Reverse.POCO.v3.ttinclude @@ -72,6 +72,7 @@ public static string ResultClassModifiers = "public"; // "public partial"; public static bool UsePascalCase = true; // This will rename the generated C# tables & properties to use PascalCase. If false table & property names will be left alone. + public static bool UsePascalCaseForEnumMembers = true; // This will rename the generated Enum Members to use PascalCase. If false Enum members will be left alone. public static bool UseDataAnnotations = false; // If true, will add data annotations to the poco classes. public static bool UsePropertyInitialisers = false; // Removes POCO constructor and instead uses C# 6 property initialisers to set defaults public static bool UseLazyLoading = true; // Marks all navigation properties as virtual or not, to support or disable EF Lazy Loading feature @@ -107,6 +108,9 @@ public static bool IncludeCodeGeneratedAttribute = false; // If true, will include the [GeneratedCode] attribute before classes, false to remove it. public static bool IncludeColumnsWithDefaults = true; // If true, will set properties to the default value from the database.ro + public static string EnumNameField = "Name"; + public static string EnumValueField = "Id"; + // Create enumerations from database tables // List the enumeration tables you want read and generated for public static List Enumerations = new List @@ -293,6 +297,21 @@ } }; + // Use the following function if you need to apply additional modifications to a enum + // Called just before UpdateEnumMember + public static Action UpdateEnum = delegate (Enumeration enumeration) + { + //enumeration.EnumAttributes.Add("[DataContract]"); + }; + + // Use the following function if you need to apply additional modifications to a enum member + public static Action UpdateEnumMember = delegate (EnumerationMember enumerationMember) + { + //enumerationMember.Attributes.Add("[EnumMember]"); + + //enumerationMember.Attributes.Add("[SomeAttribute(\"" + enumerationMember.AllValues["SomeName"] + " \")]"); + }; + // Writes any boilerplate stuff inside the POCO class body public static Func WriteInsideClassBody = delegate (Table t) { @@ -684,6 +703,8 @@ public static readonly List> TableFilters; public static readonly List> ColumnFilters; public static readonly List> StoredProcedureFilters; + public static readonly List> EnumerationTableFilters; + public static readonly List> EnumerationSchemaFilters; static FilterSettings() { @@ -691,14 +712,20 @@ TableFilters = new List>(); ColumnFilters = new List>(); StoredProcedureFilters = new List>(); + EnumerationTableFilters = new List>(); + EnumerationSchemaFilters = new List>(); } + + public static void Reset() { SchemaFilters .RemoveAll(x => true); TableFilters .RemoveAll(x => true); ColumnFilters .RemoveAll(x => true); StoredProcedureFilters.RemoveAll(x => true); + EnumerationTableFilters.RemoveAll(x => true); + EnumerationSchemaFilters.RemoveAll(x => true); } public static void AddDefaults() @@ -713,6 +740,8 @@ AddDefaultTableFilters(); AddDefaultColumnFilters(); AddDefaultStoredProcedureFilters(); + AddDefaultEnumerationTableFilters(); + AddDefaultEnumerationSchemaFilters(); } public static void CheckSettings() @@ -783,6 +812,24 @@ new HasNameFilter(FilterType.StoredProcedure) }); } + + public static void AddDefaultEnumerationTableFilters() + { + EnumerationTableFilters.AddRange(new List> + { + // Add your own code to these custom filter classes + new EnumerationTableFilter(), + }); + } + + public static void AddDefaultEnumerationSchemaFilters() + { + EnumerationSchemaFilters.AddRange(new List> + { + // Add your own code to these custom filter classes + new EnumerationSchemaFilter(), + }); + } } /// @@ -796,6 +843,9 @@ protected readonly List> TableFilters; protected readonly List> ColumnFilters; protected readonly List> StoredProcedureFilters; + protected readonly List> EnumerationTableFilters; + protected readonly List>EnumerationSchemaFilters; + private bool _hasMergedIncludeFilters; public SingleContextFilter() @@ -806,10 +856,12 @@ IncludeScalarValuedFunctions = FilterSettings.IncludeScalarValuedFunctions; IncludeStoredProcedures = IncludeScalarValuedFunctions || IncludeTableValuedFunctions || FilterSettings.IncludeStoredProcedures; - SchemaFilters = FilterSettings.SchemaFilters; - TableFilters = FilterSettings.TableFilters; - ColumnFilters = FilterSettings.ColumnFilters; - StoredProcedureFilters = FilterSettings.StoredProcedureFilters; + SchemaFilters = FilterSettings.SchemaFilters; + TableFilters = FilterSettings.TableFilters; + ColumnFilters = FilterSettings.ColumnFilters; + StoredProcedureFilters = FilterSettings.StoredProcedureFilters; + EnumerationTableFilters = FilterSettings.EnumerationTableFilters; + EnumerationSchemaFilters = FilterSettings.EnumerationSchemaFilters; _hasMergedIncludeFilters = false; EnumDefinitions = new List(); @@ -828,9 +880,24 @@ if (schema != null) return SchemaFilters.Any(filter => filter.IsExcluded(schema)); + var enumSchemaSource = item as EnumSchemaSource; + if (enumSchemaSource != null) + { + return EnumerationSchemaFilters.Any(filter => filter.IsExcluded(enumSchemaSource)); + } + + + var enumTableSource = item as EnumTableSource; + if (enumTableSource != null) + { + return EnumerationTableFilters.Any(filter => filter.IsExcluded(enumTableSource)) || EnumerationSchemaFilters.Any(filter => filter.IsExcluded(enumTableSource.Schema)); + } + var table = item as Table; if (table != null) + { return TableFilters.Any(filter => filter.IsExcluded(table)) || SchemaFilters.Any(filter => filter.IsExcluded(table.Schema)); + } var column = item as Column; if (column != null) @@ -876,6 +943,16 @@ Settings.UpdateColumn?.Invoke(column, table, EnumDefinitions); } + public override void UpdateEnum(Enumeration enumeration) + { + Settings.UpdateEnum?.Invoke(enumeration); + } + + public override void UpdateEnumMember(EnumerationMember enumerationMember) + { + Settings.UpdateEnumMember?.Invoke(enumerationMember); + } + public override void ViewProcessing(Table view) { // Callback to Settings, which can be set within .tt @@ -934,6 +1011,9 @@ MergeIncludeFilters(TableFilters); MergeIncludeFilters(ColumnFilters); MergeIncludeFilters(StoredProcedureFilters); + + MergeIncludeFilters(EnumerationSchemaFilters); + MergeIncludeFilters(EnumerationTableFilters); } private static void MergeIncludeFilters(List> filters) @@ -1419,15 +1499,50 @@ public class Enumeration { public readonly string EnumName; - public readonly List> Items; + public readonly List Items; - public Enumeration(string enumName, List> items) + public List EnumAttributes = new List(); + + public Enumeration(string enumName, List items) { EnumName = enumName; Items = items; } } + public class EnumerationMember + { + public readonly string Key; + public readonly string Value; + public readonly Dictionary AllValues; + + public List Attributes = new List(); + + public EnumerationMember(string key, string value, Dictionary allValues) + { + Key = key; + Value = value; + AllValues = allValues; + } + } + public class EnumSchemaSource : EntityName + { + public EnumSchemaSource(string dbName) + { + DbName = dbName; + } + } + public class EnumTableSource : EntityName + { + public EnumSchemaSource Schema; + + public EnumTableSource(EnumSchemaSource schema, string dbName) + { + Schema = schema; + DbName = dbName; + } + } + public class CustomFileManager : IFileManager { private readonly List _blocks; @@ -1800,6 +1915,8 @@ public abstract string MappingTableRename(string mappingTable, string tableName, string entityName); public abstract void UpdateTable(Table table); public abstract void UpdateColumn(Column column, Table table); + public abstract void UpdateEnum(Enumeration enumeration); + public abstract void UpdateEnumMember(EnumerationMember enumerationMember); public abstract void ViewProcessing(Table view); public abstract string StoredProcedureRename(StoredProcedure sp); public abstract string StoredProcedureReturnModelRename(string name, StoredProcedure sp); @@ -1905,12 +2022,42 @@ return _filters.Any(x => x.Value.IncludeScalarValuedFunctions); } } + + public class EnumerationSchemaFilter : IFilterType + { + // Filtering of stored procedures using a function. + // Return true to exclude the stored procedure, return false to include it. + public bool IsExcluded(EnumSchemaSource enumSchemaSource) + { + // Example: Exclude any stored procedure in dbo schema with "order" in its name. + //if(sp.Schema.DbName.Equals("dbo", StringComparison.InvariantCultureIgnoreCase) && sp.NameHumanCase.ToLowerInvariant().Contains("order")) + // return false; + + return false; + } + } + + public class EnumerationTableFilter : IFilterType + { + // Filtering of stored procedures using a function. + // Return true to exclude the stored procedure, return false to include it. + public bool IsExcluded(EnumTableSource enumTableSource) + { + // Example: Exclude any stored procedure in dbo schema with "order" in its name. + //if(sp.Schema.DbName.Equals("dbo", StringComparison.InvariantCultureIgnoreCase) && sp.NameHumanCase.ToLowerInvariant().Contains("order")) + // return false; + + return false; + } + } public enum FilterType { Schema, // Can only be used on Schema Table, // Can only used on Tables Column, // Can only used on Columns - StoredProcedure // Can only used on Stored Procedures + StoredProcedure,// Can only used on Stored Procedures + EnumSchema, // Can only used on Enums + EnumTable // Can only used on Enums } public class HasNameFilter : IFilterType @@ -1960,6 +2107,8 @@ string MappingTableRename(string mappingTable, string tableName, string entityName); void UpdateTable(Table table); void UpdateColumn(Column column, Table table); + void UpdateEnum(Enumeration enumeration); + void UpdateEnumMember(EnumerationMember enumerationMember); void ViewProcessing(Table view); string StoredProcedureRename(StoredProcedure sp); string StoredProcedureReturnModelRename(string name, StoredProcedure sp); @@ -2330,6 +2479,16 @@ Settings.UpdateColumn?.Invoke(column, table, null); } + public override void UpdateEnum(Enumeration enumeration) + { + + } + + public override void UpdateEnumMember(EnumerationMember enumerationMember) + { + + } + public override void ViewProcessing(Table view) { // Find the multi-context settings for this view @@ -4059,6 +4218,19 @@ filterKeyValuePair.Value.Enums.AddRange(enumerations); } } + + foreach (var filterKeyValuePair in FilterList.GetFilters()) + { + var filter = filterKeyValuePair.Value; + foreach (var enumeration in filter.Enums) + { + filter.UpdateEnum(enumeration); + foreach (var enumerationMember in enumeration.Items) + { + filter.UpdateEnumMember(enumerationMember); + } + } + } } catch (Exception x) { @@ -4129,6 +4301,7 @@ //foreach (var ri in rawIndexes.OrderBy(x => x.TableName).ThenBy(x => x.IndexName)) Console.WriteLine(ri.Dump()); //foreach (var rfk in rawForeignKeys) Console.WriteLine(rfk.Dump()); + AddTablesToEnums(rawTables); AddTablesToFilters(rawTables); IdentifyUniqueForeignKeys(rawIndexes, rawForeignKeys); AddIndexesToFilters(rawIndexes); @@ -4152,6 +4325,53 @@ } } + private void AddTablesToEnums(List rawTables) + { + if (rawTables == null || !rawTables.Any()) + return; + + var tablesNames = rawTables + .Select(x => new { x.SchemaName, x.TableName, x.IsView }) + .Distinct() + .OrderBy(x => x.SchemaName) + .ThenBy(x => x.TableName) + .ToList(); + + foreach (var filterKeyValuePair in FilterList.GetFilters()) + { + var filter = filterKeyValuePair.Value; + + foreach (var tn in tablesNames) + { + var exclude = false; + + var enumSchemaSource = new EnumSchemaSource(tn.SchemaName); + if (filter.IsExcluded(enumSchemaSource)) + { + exclude = true; + } + + var enumTableSource = new EnumTableSource(enumSchemaSource, tn.TableName); + if (filter.IsExcluded(enumTableSource)) + { + exclude = true; + } + + if (exclude) + { + continue; + } + + var enumeration = DatabaseReader.ReadEnum(enumTableSource); + + if (enumeration == null) + return; // No enums in database + + filterKeyValuePair.Value.Enums.Add(enumeration); + } + } + } + public static void IdentifyUniqueForeignKeys(List rawIndexes, List rawForeignKeys) { if (rawIndexes == null || rawForeignKeys == null || !rawIndexes.Any() || !rawForeignKeys.Any()) @@ -12608,6 +12828,24 @@ and limitations under the License. return result; } + public Enumeration ReadEnum(EnumTableSource enumTableSource) + { + using (var conn = _factory.CreateConnection()) + { + if (conn == null) + return null; + + conn.ConnectionString = Settings.ConnectionString; + conn.Open(); + + var cmd = GetCmd(conn); + if (cmd == null) + return null; + + return CreateEnumeration(cmd, enumTableSource.NameHumanCase, enumTableSource.NameHumanCase, Settings.EnumNameField, Settings.EnumValueField); + } + } + public List ReadEnums(List enums) { var result = new List(); @@ -12623,50 +12861,66 @@ and limitations under the License. if (cmd == null) return result; - foreach (var e in enums) - { - var sql = EnumSQL(e.Table, e.NameField, e.ValueField); - if (string.IsNullOrEmpty(sql)) - continue; + result.AddRange(enums.Select(e => CreateEnumeration(cmd, e.Name, e.Table, e.NameField, e.ValueField)) + .Where(enumeration => enumeration != null)); + } + return result; + } - cmd.CommandText = sql; + private Enumeration CreateEnumeration(DbCommand cmd, string enumName, string tableName, string nameField, string valueField) + { + var sql = EnumSQL(tableName, nameField, valueField); + if (string.IsNullOrEmpty(sql)) + return null; - try - { - using (var rdr = cmd.ExecuteReader()) - { - var items = new List>(); - while (rdr.Read()) - { - var name = rdr["NameField"].ToString().Trim(); - if (string.IsNullOrEmpty(name)) - continue; + cmd.CommandText = sql; - name = RemoveNonAlphanumerics.Replace(name, string.Empty); - name = Inflector.ToTitleCase(name).Replace(" ", "").Trim(); - if (string.IsNullOrEmpty(name)) - continue; + try + { + using (var rdr = cmd.ExecuteReader()) + { + var items = new List(); - var value = rdr["ValueField"].ToString().Trim(); - if (string.IsNullOrEmpty(value)) - continue; + while (rdr.Read()) + { + var name = rdr["NameField"].ToString().Trim(); + if (string.IsNullOrEmpty(name)) + continue; - items.Add(new KeyValuePair(name, value)); - } + name = RemoveNonAlphanumerics.Replace(name, string.Empty); + name = (Settings.UsePascalCaseForEnumMembers ? Inflector.ToTitleCase(name) : name) + .Replace(" ", string.Empty).Trim(); + if (string.IsNullOrEmpty(name)) + continue; + + var value = rdr["ValueField"].ToString().Trim(); + if (string.IsNullOrEmpty(value)) + continue; - if(items.Any()) - result.Add(new Enumeration(e.Name, items)); + var allValues = new Dictionary(); + for (var n = 2; n < rdr.FieldCount; ++n) + { + var o = rdr.GetValue(n); + allValues.Add(rdr.GetName(n), o != DBNull.Value ? o : null); } + + items.Add(new EnumerationMember(name, value, allValues)); } - catch (Exception) + + if (items.Any()) { - // Enum table does not exist in database, skip + return new Enumeration(enumName, items); } } } - return result; + catch (Exception) + { + // Enum table does not exist in database, skip + } + + return null; } - + public List ReadSequences() { if (DatabaseReaderPlugin != null) @@ -13539,7 +13793,7 @@ ORDER BY R.specific_schema, R.routine_name, R.routine_type;"; protected override string EnumSQL(string table, string nameField, string valueField) { - return string.Format(@"SELECT ""{0}"" as ""NameField"", ""{1}"" as ""ValueField"" FROM ""{2}"";", nameField, valueField, table); + return string.Format(@"SELECT ""{0}"" as ""NameField"", ""{1}"" as ""ValueField"", * FROM ""{2}"";", nameField, valueField, table); } protected override string SequenceSQL() @@ -14088,7 +14342,7 @@ SELECT * FROM MultiContext.ForeignKey;"; protected override string EnumSQL(string table, string nameField, string valueField) { - return string.Format("SELECT {0} as NameField, {1} as ValueField FROM {2};", nameField, valueField, table); + return string.Format("SELECT {0} as NameField, {1} as ValueField, * FROM {2};", nameField, valueField, table); } protected override string SequenceSQL() @@ -14608,7 +14862,7 @@ SELECT * FROM MultiContext.ForeignKey;"; protected override string EnumSQL(string table, string nameField, string valueField) { - return string.Format("SELECT {0} as NameField, {1} as ValueField FROM {2};", nameField, valueField, table); + return string.Format("SELECT {0} as NameField, {1} as ValueField, * FROM {2};", nameField, valueField, table); } protected override string SequenceSQL() @@ -17620,9 +17874,15 @@ using {{this}};{{#newline}} public override string Enums() { return @" +{{#each EnumAttributes}} +{{this}}{{#newline}} +{{/each}} public enum {{EnumName}}{{#newline}} {{{#newline}} {{#each Items}} + {{#each Attributes}} + {{this}}{{#newline}} + {{/each}} {{Key}} = {{Value}},{{#newline}} {{/each}} }{{#newline}} @@ -18973,9 +19233,15 @@ using {{this}};{{#newline}} public override string Enums() { return @" +{{#each EnumAttributes}} +{{this}}{{#newline}} +{{/each}} public enum {{EnumName}}{{#newline}} {{{#newline}} {{#each Items}} + {{#each Attributes}} + {{this}}{{#newline}} + {{/each}} {{Key}} = {{Value}},{{#newline}} {{/each}} }{{#newline}} @@ -20446,9 +20712,15 @@ using {{this}};{{#newline}} public override string Enums() { return @" +{{#each EnumAttributes}} +{{this}}{{#newline}} +{{/each}} public enum {{EnumName}}{{#newline}} {{{#newline}} {{#each Items}} + {{#each Attributes}} + {{this}}{{#newline}} + {{/each}} {{Key}} = {{Value}},{{#newline}} {{/each}} }{{#newline}} @@ -21896,9 +22168,15 @@ using {{this}};{{#newline}} public override string Enums() { return @" +{{#each EnumAttributes}} +{{this}}{{#newline}} +{{/each}} public enum {{EnumName}}{{#newline}} {{{#newline}} {{#each Items}} + {{#each Attributes}} + {{this}}{{#newline}} + {{/each}} {{Key}} = {{Value}},{{#newline}} {{/each}} }{{#newline}} diff --git a/Generator.Tests.Unit/FilterTests.cs b/Generator.Tests.Unit/FilterTests.cs index e3354764..3c10a660 100644 --- a/Generator.Tests.Unit/FilterTests.cs +++ b/Generator.Tests.Unit/FilterTests.cs @@ -59,6 +59,10 @@ public void SetUp() // Stored procedure [TestCase("ab", FilterType.StoredProcedure, false)] + + // Enum + [TestCase("Enum.PriceType", FilterType.EnumTable, false)] + [TestCase("Enum.ProductType", FilterType.EnumTable, true)] public void IsTypeExcluded(string name, FilterType filterType, bool expectedExclusion) { var item = CreateType(name, filterType); @@ -66,19 +70,25 @@ public void IsTypeExcluded(string name, FilterType filterType, bool expectedExcl Assert.AreEqual(expectedExclusion, isExcluded); } - private EntityName CreateType(string name, FilterType filterType) + private static EntityName CreateType(string name, FilterType filterType) { + string[] split; switch (filterType) { case FilterType.Schema: return new Schema(name); case FilterType.Table: - var split = name.Split('.'); + split = name.Split('.'); return new Table(null, new Schema(split[0]), split[1], false); case FilterType.Column: return new Column { DbName = name }; case FilterType.StoredProcedure: return new StoredProcedure { Schema = new Schema("dbo"), DbName = name }; + case FilterType.EnumSchema: + return new EnumSchemaSource(name); + case FilterType.EnumTable: + split = name.Split('.'); + return new EnumTableSource(new EnumSchemaSource(split[0]), split[1]); default: throw new ArgumentOutOfRangeException(nameof(filterType), filterType, null); } diff --git a/Generator.Tests.Unit/TestDbContextFilter.cs b/Generator.Tests.Unit/TestDbContextFilter.cs index 341a7a42..ace0e777 100644 --- a/Generator.Tests.Unit/TestDbContextFilter.cs +++ b/Generator.Tests.Unit/TestDbContextFilter.cs @@ -8,6 +8,16 @@ public class TestContextFilter : SingleContextFilter { public TestContextFilter() { + EnumerationSchemaFilters.AddRange(new List> + { + new RegexIncludeFilter("^Enum$") + }); + + EnumerationTableFilters.AddRange(new List> + { + new RegexExcludeFilter("^ProductType$") + }); + SchemaFilters.AddRange(new List> { // Only include the schemas 'dbo' and 'events' diff --git a/Generator/EnumSchemaSource.cs b/Generator/EnumSchemaSource.cs new file mode 100644 index 00000000..4eb8eb6c --- /dev/null +++ b/Generator/EnumSchemaSource.cs @@ -0,0 +1,10 @@ +namespace Efrpg +{ + public class EnumSchemaSource : EntityName + { + public EnumSchemaSource(string dbName) + { + DbName = dbName; + } + } +} diff --git a/Generator/EnumTableSource.cs b/Generator/EnumTableSource.cs new file mode 100644 index 00000000..fc1a2833 --- /dev/null +++ b/Generator/EnumTableSource.cs @@ -0,0 +1,13 @@ +namespace Efrpg +{ + public class EnumTableSource : EntityName + { + public EnumSchemaSource Schema; + + public EnumTableSource(EnumSchemaSource schema, string dbName) + { + Schema = schema; + DbName = dbName; + } + } +} diff --git a/Generator/Filtering/EnumerationSchemaFilter.cs b/Generator/Filtering/EnumerationSchemaFilter.cs new file mode 100644 index 00000000..e644cd16 --- /dev/null +++ b/Generator/Filtering/EnumerationSchemaFilter.cs @@ -0,0 +1,18 @@ +using System; + +namespace Efrpg.Filtering +{ + public class EnumerationSchemaFilter : IFilterType + { + // Filtering of stored procedures using a function. + // Return true to exclude the stored procedure, return false to include it. + public bool IsExcluded(EnumSchemaSource enumSchemaSource) + { + // Example: Exclude any stored procedure in dbo schema with "order" in its name. + //if(sp.Schema.DbName.Equals("dbo", StringComparison.InvariantCultureIgnoreCase) && sp.NameHumanCase.ToLowerInvariant().Contains("order")) + // return false; + + return false; + } + } +} \ No newline at end of file diff --git a/Generator/Filtering/EnumerationTableFilter.cs b/Generator/Filtering/EnumerationTableFilter.cs new file mode 100644 index 00000000..9cbf8588 --- /dev/null +++ b/Generator/Filtering/EnumerationTableFilter.cs @@ -0,0 +1,18 @@ +using System; + +namespace Efrpg.Filtering +{ + public class EnumerationTableFilter : IFilterType + { + // Filtering of stored procedures using a function. + // Return true to exclude the stored procedure, return false to include it. + public bool IsExcluded(EnumTableSource enumTableSource) + { + // Example: Exclude any stored procedure in dbo schema with "order" in its name. + //if(sp.Schema.DbName.Equals("dbo", StringComparison.InvariantCultureIgnoreCase) && sp.NameHumanCase.ToLowerInvariant().Contains("order")) + // return false; + + return false; + } + } +} \ No newline at end of file diff --git a/Generator/Filtering/FilterSettings.cs b/Generator/Filtering/FilterSettings.cs index cefe0824..79f2aa3d 100644 --- a/Generator/Filtering/FilterSettings.cs +++ b/Generator/Filtering/FilterSettings.cs @@ -22,6 +22,8 @@ public static class FilterSettings public static readonly List> TableFilters; public static readonly List> ColumnFilters; public static readonly List> StoredProcedureFilters; + public static readonly List> EnumerationTableFilters; + public static readonly List> EnumerationSchemaFilters; static FilterSettings() { @@ -29,14 +31,20 @@ static FilterSettings() TableFilters = new List>(); ColumnFilters = new List>(); StoredProcedureFilters = new List>(); + EnumerationTableFilters = new List>(); + EnumerationSchemaFilters = new List>(); } + + public static void Reset() { SchemaFilters .RemoveAll(x => true); TableFilters .RemoveAll(x => true); ColumnFilters .RemoveAll(x => true); StoredProcedureFilters.RemoveAll(x => true); + EnumerationTableFilters.RemoveAll(x => true); + EnumerationSchemaFilters.RemoveAll(x => true); } public static void AddDefaults() @@ -51,6 +59,8 @@ public static void AddDefaults() AddDefaultTableFilters(); AddDefaultColumnFilters(); AddDefaultStoredProcedureFilters(); + AddDefaultEnumerationTableFilters(); + AddDefaultEnumerationSchemaFilters(); } public static void CheckSettings() @@ -121,5 +131,23 @@ public static void AddDefaultStoredProcedureFilters() new HasNameFilter(FilterType.StoredProcedure) }); } + + public static void AddDefaultEnumerationTableFilters() + { + EnumerationTableFilters.AddRange(new List> + { + // Add your own code to these custom filter classes + new EnumerationTableFilter(), + }); + } + + public static void AddDefaultEnumerationSchemaFilters() + { + EnumerationSchemaFilters.AddRange(new List> + { + // Add your own code to these custom filter classes + new EnumerationSchemaFilter(), + }); + } } } \ No newline at end of file diff --git a/Generator/Filtering/FilterType.cs b/Generator/Filtering/FilterType.cs index 9ca033bb..329fb003 100644 --- a/Generator/Filtering/FilterType.cs +++ b/Generator/Filtering/FilterType.cs @@ -5,6 +5,8 @@ public enum FilterType Schema, // Can only be used on Schema Table, // Can only used on Tables Column, // Can only used on Columns - StoredProcedure // Can only used on Stored Procedures + StoredProcedure,// Can only used on Stored Procedures + EnumSchema, // Can only used on Enums + EnumTable // Can only used on Enums } } \ No newline at end of file diff --git a/Generator/Filtering/SingleContextFilter.cs b/Generator/Filtering/SingleContextFilter.cs index 3e934ffe..112e711f 100644 --- a/Generator/Filtering/SingleContextFilter.cs +++ b/Generator/Filtering/SingleContextFilter.cs @@ -14,6 +14,9 @@ public class SingleContextFilter : DbContextFilter protected readonly List> TableFilters; protected readonly List> ColumnFilters; protected readonly List> StoredProcedureFilters; + protected readonly List> EnumerationTableFilters; + protected readonly List>EnumerationSchemaFilters; + private bool _hasMergedIncludeFilters; public SingleContextFilter() @@ -24,10 +27,12 @@ public SingleContextFilter() IncludeScalarValuedFunctions = FilterSettings.IncludeScalarValuedFunctions; IncludeStoredProcedures = IncludeScalarValuedFunctions || IncludeTableValuedFunctions || FilterSettings.IncludeStoredProcedures; - SchemaFilters = FilterSettings.SchemaFilters; - TableFilters = FilterSettings.TableFilters; - ColumnFilters = FilterSettings.ColumnFilters; - StoredProcedureFilters = FilterSettings.StoredProcedureFilters; + SchemaFilters = FilterSettings.SchemaFilters; + TableFilters = FilterSettings.TableFilters; + ColumnFilters = FilterSettings.ColumnFilters; + StoredProcedureFilters = FilterSettings.StoredProcedureFilters; + EnumerationTableFilters = FilterSettings.EnumerationTableFilters; + EnumerationSchemaFilters = FilterSettings.EnumerationSchemaFilters; _hasMergedIncludeFilters = false; EnumDefinitions = new List(); @@ -46,9 +51,24 @@ public override bool IsExcluded(EntityName item) if (schema != null) return SchemaFilters.Any(filter => filter.IsExcluded(schema)); + var enumSchemaSource = item as EnumSchemaSource; + if (enumSchemaSource != null) + { + return EnumerationSchemaFilters.Any(filter => filter.IsExcluded(enumSchemaSource)); + } + + + var enumTableSource = item as EnumTableSource; + if (enumTableSource != null) + { + return EnumerationTableFilters.Any(filter => filter.IsExcluded(enumTableSource)) || EnumerationSchemaFilters.Any(filter => filter.IsExcluded(enumTableSource.Schema)); + } + var table = item as Table; if (table != null) + { return TableFilters.Any(filter => filter.IsExcluded(table)) || SchemaFilters.Any(filter => filter.IsExcluded(table.Schema)); + } var column = item as Column; if (column != null) @@ -162,6 +182,9 @@ private void MergeIncludeFilters() MergeIncludeFilters(TableFilters); MergeIncludeFilters(ColumnFilters); MergeIncludeFilters(StoredProcedureFilters); + + MergeIncludeFilters(EnumerationSchemaFilters); + MergeIncludeFilters(EnumerationTableFilters); } private static void MergeIncludeFilters(List> filters) diff --git a/Generator/Generator.csproj b/Generator/Generator.csproj index 926e80c4..e4e76fbf 100644 --- a/Generator/Generator.csproj +++ b/Generator/Generator.csproj @@ -62,6 +62,9 @@ + + + @@ -79,6 +82,7 @@ + diff --git a/Generator/Generators/Generator.cs b/Generator/Generators/Generator.cs index e52f4a63..f8233480 100644 --- a/Generator/Generators/Generator.cs +++ b/Generator/Generators/Generator.cs @@ -282,6 +282,7 @@ public void LoadTables() //foreach (var ri in rawIndexes.OrderBy(x => x.TableName).ThenBy(x => x.IndexName)) Console.WriteLine(ri.Dump()); //foreach (var rfk in rawForeignKeys) Console.WriteLine(rfk.Dump()); + AddTablesToEnums(rawTables); AddTablesToFilters(rawTables); IdentifyUniqueForeignKeys(rawIndexes, rawForeignKeys); AddIndexesToFilters(rawIndexes); @@ -305,6 +306,53 @@ public void LoadTables() } } + private void AddTablesToEnums(List rawTables) + { + if (rawTables == null || !rawTables.Any()) + return; + + var tablesNames = rawTables + .Select(x => new { x.SchemaName, x.TableName, x.IsView }) + .Distinct() + .OrderBy(x => x.SchemaName) + .ThenBy(x => x.TableName) + .ToList(); + + foreach (var filterKeyValuePair in FilterList.GetFilters()) + { + var filter = filterKeyValuePair.Value; + + foreach (var tn in tablesNames) + { + var exclude = false; + + var enumSchemaSource = new EnumSchemaSource(tn.SchemaName); + if (filter.IsExcluded(enumSchemaSource)) + { + exclude = true; + } + + var enumTableSource = new EnumTableSource(enumSchemaSource, tn.TableName); + if (filter.IsExcluded(enumTableSource)) + { + exclude = true; + } + + if (exclude) + { + continue; + } + + var enumeration = DatabaseReader.ReadEnum(enumTableSource); + + if (enumeration == null) + return; // No enums in database + + filterKeyValuePair.Value.Enums.Add(enumeration); + } + } + } + public static void IdentifyUniqueForeignKeys(List rawIndexes, List rawForeignKeys) { if (rawIndexes == null || rawForeignKeys == null || !rawIndexes.Any() || !rawForeignKeys.Any()) diff --git a/Generator/Readers/DatabaseReader.cs b/Generator/Readers/DatabaseReader.cs index 01be1c92..89422b30 100644 --- a/Generator/Readers/DatabaseReader.cs +++ b/Generator/Readers/DatabaseReader.cs @@ -780,6 +780,24 @@ private Dictionary ReadAllFields(DbDataReader rdr) return result; } + public Enumeration ReadEnum(EnumTableSource enumTableSource) + { + using (var conn = _factory.CreateConnection()) + { + if (conn == null) + return null; + + conn.ConnectionString = Settings.ConnectionString; + conn.Open(); + + var cmd = GetCmd(conn); + if (cmd == null) + return null; + + return CreateEnumeration(cmd, enumTableSource.NameHumanCase, enumTableSource.NameHumanCase, Settings.EnumNameField, Settings.EnumValueField); + } + } + public List ReadEnums(List enums) { var result = new List(); @@ -795,60 +813,66 @@ public List ReadEnums(List enums) if (cmd == null) return result; - foreach (var e in enums) - { - var sql = EnumSQL(e.Table, e.NameField, e.ValueField); - if (string.IsNullOrEmpty(sql)) - continue; + result.AddRange(enums.Select(e => CreateEnumeration(cmd, e.Name, e.Table, e.NameField, e.ValueField)) + .Where(enumeration => enumeration != null)); + } + return result; + } - cmd.CommandText = sql; + private Enumeration CreateEnumeration(DbCommand cmd, string enumName, string tableName, string nameField, string valueField) + { + var sql = EnumSQL(tableName, nameField, valueField); + if (string.IsNullOrEmpty(sql)) + return null; - try + cmd.CommandText = sql; + + try + { + using (var rdr = cmd.ExecuteReader()) + { + var items = new List(); + + while (rdr.Read()) { - using (var rdr = cmd.ExecuteReader()) - { - var items = new List(); + var name = rdr["NameField"].ToString().Trim(); + if (string.IsNullOrEmpty(name)) + continue; - while (rdr.Read()) - { - var name = rdr["NameField"].ToString().Trim(); - if (string.IsNullOrEmpty(name)) - continue; - - name = RemoveNonAlphanumerics.Replace(name, string.Empty); - name = (Settings.UsePascalCaseForEnumMembers ? Inflector.ToTitleCase(name) : name).Replace(" ", string.Empty).Trim(); - if (string.IsNullOrEmpty(name)) - continue; - - var value = rdr["ValueField"].ToString().Trim(); - if (string.IsNullOrEmpty(value)) - continue; - - var allValues = new Dictionary(); - for (var n = 2; n < rdr.FieldCount; ++n) - { - var o = rdr.GetValue(n); - allValues.Add(rdr.GetName(n), o != DBNull.Value ? o : null); - } - - items.Add(new EnumerationMember(name, value, allValues)); - } + name = RemoveNonAlphanumerics.Replace(name, string.Empty); + name = (Settings.UsePascalCaseForEnumMembers ? Inflector.ToTitleCase(name) : name) + .Replace(" ", string.Empty).Trim(); + if (string.IsNullOrEmpty(name)) + continue; - if(items.Any()) - { - result.Add(new Enumeration(e.Name, items)); - } + var value = rdr["ValueField"].ToString().Trim(); + if (string.IsNullOrEmpty(value)) + continue; + + var allValues = new Dictionary(); + for (var n = 2; n < rdr.FieldCount; ++n) + { + var o = rdr.GetValue(n); + allValues.Add(rdr.GetName(n), o != DBNull.Value ? o : null); } + + items.Add(new EnumerationMember(name, value, allValues)); } - catch (Exception) + + if (items.Any()) { - // Enum table does not exist in database, skip + return new Enumeration(enumName, items); } } } - return result; + catch (Exception) + { + // Enum table does not exist in database, skip + } + + return null; } - + public List ReadSequences() { if (DatabaseReaderPlugin != null) diff --git a/Generator/Settings.cs b/Generator/Settings.cs index f283f9c1..067e5950 100644 --- a/Generator/Settings.cs +++ b/Generator/Settings.cs @@ -82,6 +82,9 @@ public static class Settings public static bool IncludeCodeGeneratedAttribute = false; // If true, will include the [GeneratedCode] attribute before classes, false to remove it. public static bool IncludeColumnsWithDefaults = true; // If true, will set properties to the default value from the database.ro + public static string EnumNameField = "Name"; + public static string EnumValueField = "Id"; + // Create enumerations from database tables // List the enumeration tables you want read and generated for public static List Enumerations = new List diff --git a/Tester.Integration.EfCore3/File based templates/Templates.EF6/Enums.mustache b/Tester.Integration.EfCore3/File based templates/Templates.EF6/Enums.mustache index 40dce642..45b5583f 100644 --- a/Tester.Integration.EfCore3/File based templates/Templates.EF6/Enums.mustache +++ b/Tester.Integration.EfCore3/File based templates/Templates.EF6/Enums.mustache @@ -2,8 +2,7 @@ {{this}}{{#newline}} {{/each}} public enum {{EnumName}}{{#newline}} -{{{ -#newline}} +{{{#newline}} {{#each Items}} {{#each Attributes}} {{this}}{{#newline}} diff --git a/Tester.Integration.EfCore3/File based templates/Templates.EFCore3/Enums.mustache b/Tester.Integration.EfCore3/File based templates/Templates.EFCore3/Enums.mustache index 40dce642..45b5583f 100644 --- a/Tester.Integration.EfCore3/File based templates/Templates.EFCore3/Enums.mustache +++ b/Tester.Integration.EfCore3/File based templates/Templates.EFCore3/Enums.mustache @@ -2,8 +2,7 @@ {{this}}{{#newline}} {{/each}} public enum {{EnumName}}{{#newline}} -{{{ -#newline}} +{{{#newline}} {{#each Items}} {{#each Attributes}} {{this}}{{#newline}}