diff --git a/EfEnumToLookup/LookupGenerator/EnumParser.cs b/EfEnumToLookup/LookupGenerator/EnumParser.cs index 3bd9351..3d3f7c2 100644 --- a/EfEnumToLookup/LookupGenerator/EnumParser.cs +++ b/EfEnumToLookup/LookupGenerator/EnumParser.cs @@ -57,6 +57,7 @@ public IEnumerable GetLookupValues(Type lookup) { Id = (int)numericValue, Name = EnumName(value), + Description = EnumDescriptionValue(value) }); } return values; @@ -70,12 +71,6 @@ public IEnumerable GetLookupValues(Type lookup) /// private string EnumName(Enum value) { - var description = EnumDescriptionValue(value); - if (description != null) - { - return description; - } - var name = value.ToString(); if (SplitWords) diff --git a/EfEnumToLookup/LookupGenerator/EnumToLookup.cs b/EfEnumToLookup/LookupGenerator/EnumToLookup.cs index 794c933..c443119 100644 --- a/EfEnumToLookup/LookupGenerator/EnumToLookup.cs +++ b/EfEnumToLookup/LookupGenerator/EnumToLookup.cs @@ -29,6 +29,7 @@ public EnumToLookup() { // set default behaviour, can be overridden by setting properties on object before calling Apply() NameFieldLength = 255; + DescriptionFieldLength = 255; TableNamePrefix = "Enum_"; _enumParser = new EnumParser { SplitWords = true }; UseTransaction = true; @@ -50,6 +51,12 @@ public bool SplitWords /// public int NameFieldLength { get; set; } + /// + /// The size of the Description field that will be added to the generated lookup tables. + /// Adjust to suit your data if required, defaults to 255. + /// + public int DescriptionFieldLength { get; set; } + /// /// Prefix to add to all the generated tables to separate help group them together /// and make them stand out as different from other tables. @@ -114,6 +121,7 @@ private IDbHandler GetDbHandler() IDbHandler dbHandler = new SqlServerHandler { NameFieldLength = NameFieldLength, + DescriptionFieldLength = DescriptionFieldLength, TableNamePrefix = TableNamePrefix, TableNameSuffix = TableNameSuffix, UseTransaction = UseTransaction, diff --git a/EfEnumToLookup/LookupGenerator/IDbHandler.cs b/EfEnumToLookup/LookupGenerator/IDbHandler.cs index b404f5b..7c28f32 100644 --- a/EfEnumToLookup/LookupGenerator/IDbHandler.cs +++ b/EfEnumToLookup/LookupGenerator/IDbHandler.cs @@ -12,6 +12,12 @@ internal interface IDbHandler /// int NameFieldLength { get; set; } + /// + /// The size of the Description field that will be added to the generated lookup tables. + /// Adjust to suit your data if required. + /// + int DescriptionFieldLength { get; set; } + /// /// Prefix to add to all the generated tables to separate help group them together /// and make them stand out as different from other tables. diff --git a/EfEnumToLookup/LookupGenerator/LookupValue.cs b/EfEnumToLookup/LookupGenerator/LookupValue.cs index ac1c0ae..2d9a373 100644 --- a/EfEnumToLookup/LookupGenerator/LookupValue.cs +++ b/EfEnumToLookup/LookupGenerator/LookupValue.cs @@ -4,5 +4,6 @@ internal class LookupValue { public int Id { get; set; } public string Name { get; set; } + public string Description { get; set; } } } diff --git a/EfEnumToLookup/LookupGenerator/SqlServerHandler.cs b/EfEnumToLookup/LookupGenerator/SqlServerHandler.cs index 12b5289..6d3af8f 100644 --- a/EfEnumToLookup/LookupGenerator/SqlServerHandler.cs +++ b/EfEnumToLookup/LookupGenerator/SqlServerHandler.cs @@ -13,6 +13,12 @@ class SqlServerHandler : IDbHandler /// public int NameFieldLength { get; set; } + /// + /// The size of the Description field that will be added to the generated lookup tables. + /// Adjust to suit your data if required, defaults to 255. + /// + public int DescriptionFieldLength { get; set; } + /// /// Prefix to add to all the generated tables to separate help group them together /// and make them stand out as different from other tables. @@ -82,12 +88,12 @@ private string CreateTables(IEnumerable enums) sql.AppendFormat( @"IF OBJECT_ID('{0}', 'U') IS NULL begin - CREATE TABLE [{0}] (Id {2} CONSTRAINT PK_{0} PRIMARY KEY, Name nvarchar({1})); + CREATE TABLE [{0}] (Id {2} CONSTRAINT PK_{0} PRIMARY KEY, Name nvarchar({1}), Description nvarchar({3})); exec sys.sp_addextendedproperty @name=N'MS_Description', @level0type=N'SCHEMA', @level0name=N'dbo', @level1type=N'TABLE', @level1name=N'{0}', @value=N'Automatically generated. Contents will be overwritten on app startup. Table & contents generated by https://github.com/timabell/ef-enum-to-lookup'; end ", - TableName(lookup.Name), NameFieldLength, NumericSqlType(lookup.NumericType)); + TableName(lookup.Name), NameFieldLength, NumericSqlType(lookup.NumericType), DescriptionFieldLength); } return sql.ToString(); } @@ -110,7 +116,7 @@ private string AddForeignKeys(IEnumerable refs) private string PopulateLookups(IEnumerable lookupData) { var sql = new StringBuilder(); - sql.AppendLine(string.Format("CREATE TABLE #lookups (Id int, Name nvarchar({0}) COLLATE database_default);", NameFieldLength)); + sql.AppendLine(string.Format("CREATE TABLE #lookups (Id int, Name nvarchar({0}), Description nvarchar({1}) COLLATE database_default);", NameFieldLength, DescriptionFieldLength)); foreach (var lookup in lookupData) { sql.AppendLine(PopulateLookup(lookup)); @@ -124,7 +130,7 @@ private string PopulateLookup(LookupData lookup) var sql = new StringBuilder(); foreach (var value in lookup.Values) { - sql.AppendFormat("INSERT INTO #lookups (Id, Name) VALUES ({0}, N'{1}');\r\n", value.Id, SanitizeSqlString(value.Name)); + sql.AppendFormat("INSERT INTO #lookups (Id, Name, Description) VALUES ({0}, N'{1}', N'{2}');\r\n", value.Id, SanitizeSqlString(value.Name), SanitizeSqlString(value.Description)); } sql.AppendLine(string.Format(@" @@ -133,8 +139,8 @@ MERGE INTO [{0}] dst WHEN MATCHED AND src.Name <> dst.Name collate Latin1_General_BIN2 THEN UPDATE SET Name = src.Name WHEN NOT MATCHED THEN - INSERT (Id, Name) - VALUES (src.Id, src.Name) + INSERT (Id, Name, Description) + VALUES (src.Id, src.Name, src.Description) WHEN NOT MATCHED BY SOURCE THEN DELETE ;" @@ -146,7 +152,7 @@ WHEN NOT MATCHED BY SOURCE THEN private static string SanitizeSqlString(string value) { - return value.Replace("'", "''"); + return value == null ? null : value.Replace("'", "''"); } private string TableName(string enumName) diff --git a/EfEnumToLookupTests/Tests/EnumParserTests.cs b/EfEnumToLookupTests/Tests/EnumParserTests.cs index cb04a71..a4223d5 100644 --- a/EfEnumToLookupTests/Tests/EnumParserTests.cs +++ b/EfEnumToLookupTests/Tests/EnumParserTests.cs @@ -48,7 +48,7 @@ public void ReadsByteEnum() [Test] - public void ReadsDecoratedName() + public void ReadsDecoratedDescription() { // arrange var parser = new EnumParser { SplitWords = true }; @@ -57,7 +57,7 @@ public void ReadsDecoratedName() var result = parser.GetLookupValues(typeof(DecoratedEnum)); // assert - Assert.AreEqual("Wide boy", result.Single().Name); + Assert.AreEqual("Wide boy", result.Single().Description); } private enum BareEnum diff --git a/ExampleUsage/EnumExample.cs b/ExampleUsage/EnumExample.cs index e94252a..1b6d0e9 100644 --- a/ExampleUsage/EnumExample.cs +++ b/ExampleUsage/EnumExample.cs @@ -1,5 +1,8 @@ using System; +using System.Data; using System.Data.Entity; +using System.Data.SqlClient; +using System.Linq; using EfEnumToLookup.LookupGenerator; using NUnit.Framework; @@ -56,6 +59,44 @@ public void ExampleOfGeneratingSql() context.Database.ExecuteSqlCommand(migrationSql); } } + + [Test] + public void CheckIfDescriptionColumnsExists() + { + using (var context = new MyDbContext()) + { + var enumToLookup = new EnumToLookup(); + + // if you need to get at the raw sql to run a migration separately then use: + var migrationSql = enumToLookup.GenerateMigrationSql(context); + // you'd probably want to write this to a file and then add it to source control, but for + // the purpose of demonstration we'll write it to the console instead: + Console.Out.WriteLine(migrationSql); + + // at some point you'd then run the sql (probably not like this, but this serves as a test that it's working) + context.Database.ExecuteSqlCommand(migrationSql); + + var descriptions = context.Database.SqlQuery("Select Id, Name, Description From Enum_Size"); + + var descriptionList = descriptions.ToList(); + + Assert.AreEqual(4, descriptionList.Count); + + Assert.AreEqual(string.Empty, descriptionList.Single(x => x.Id == (int)Size.Small).Description); + Assert.AreEqual("It's average", descriptionList.Single(x => x.Id == (int)Size.Medium).Description); + Assert.AreEqual(string.Empty, descriptionList.Single(x => x.Id == (int)Size.ReallyVeryBig).Description); + Assert.AreEqual("Huge you know?", descriptionList.Single(x => x.Id == (int)Size.Huge).Description); + + var shapes = context.Database.SqlQuery("Select Id, Name, Description From Enum_Shape"); + + var shapeList = shapes.ToList(); + + Assert.AreEqual(2, shapeList.Count); + + Assert.AreEqual(string.Empty, shapeList.Single(x => x.Id == (int)Shape.Square).Description); + Assert.AreEqual("Round it is!", shapeList.Single(x => x.Id == (int)Shape.Round).Description); + } + } } /// @@ -90,7 +131,7 @@ public enum Size ReallyVeryBig, // this is only fully qualified because of a name clash with NUnit, you wouldn't normally need to. - [System.ComponentModel.Description("Huge you know?")] // give it a different name in the lookup table + [System.ComponentModel.Description("Huge you know?")] Huge, [RuntimeOnly] // this won't exist in the database, handy to prevent unwanted data creeping in (enforced by foreign key constraint). @@ -100,6 +141,14 @@ public enum Size public enum Shape { Square, + [System.ComponentModel.Description("Round it is!")] Round } + + public class LookupRow + { + public int Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + } }