Skip to content

Commit

Permalink
Add description column to lookup table
Browse files Browse the repository at this point in the history
contribution from PR #35 - Svein Helge <[email protected]>
fixed-up, squashed, rewritten by Tim Abell

still stuff that needs fixing up in this commit
- see pull request for details
  • Loading branch information
timabell committed Aug 18, 2015
1 parent 4b5e905 commit b3263f5
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 16 deletions.
7 changes: 1 addition & 6 deletions EfEnumToLookup/LookupGenerator/EnumParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public IEnumerable<LookupValue> GetLookupValues(Type lookup)
{
Id = (int)numericValue,
Name = EnumName(value),
Description = EnumDescriptionValue(value)
});
}
return values;
Expand All @@ -70,12 +71,6 @@ public IEnumerable<LookupValue> GetLookupValues(Type lookup)
/// </summary>
private string EnumName(Enum value)
{
var description = EnumDescriptionValue(value);
if (description != null)
{
return description;
}

var name = value.ToString();

if (SplitWords)
Expand Down
8 changes: 8 additions & 0 deletions EfEnumToLookup/LookupGenerator/EnumToLookup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -50,6 +51,12 @@ public bool SplitWords
/// </summary>
public int NameFieldLength { get; set; }

/// <summary>
/// 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.
/// </summary>
public int DescriptionFieldLength { get; set; }

/// <summary>
/// Prefix to add to all the generated tables to separate help group them together
/// and make them stand out as different from other tables.
Expand Down Expand Up @@ -114,6 +121,7 @@ private IDbHandler GetDbHandler()
IDbHandler dbHandler = new SqlServerHandler
{
NameFieldLength = NameFieldLength,
DescriptionFieldLength = DescriptionFieldLength,
TableNamePrefix = TableNamePrefix,
TableNameSuffix = TableNameSuffix,
UseTransaction = UseTransaction,
Expand Down
6 changes: 6 additions & 0 deletions EfEnumToLookup/LookupGenerator/IDbHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ internal interface IDbHandler
/// </summary>
int NameFieldLength { get; set; }

/// <summary>
/// The size of the Description field that will be added to the generated lookup tables.
/// Adjust to suit your data if required.
/// </summary>
int DescriptionFieldLength { get; set; }

/// <summary>
/// Prefix to add to all the generated tables to separate help group them together
/// and make them stand out as different from other tables.
Expand Down
1 change: 1 addition & 0 deletions EfEnumToLookup/LookupGenerator/LookupValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ internal class LookupValue
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
}
20 changes: 13 additions & 7 deletions EfEnumToLookup/LookupGenerator/SqlServerHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ class SqlServerHandler : IDbHandler
/// </summary>
public int NameFieldLength { get; set; }

/// <summary>
/// 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.
/// </summary>
public int DescriptionFieldLength { get; set; }

/// <summary>
/// Prefix to add to all the generated tables to separate help group them together
/// and make them stand out as different from other tables.
Expand Down Expand Up @@ -82,12 +88,12 @@ private string CreateTables(IEnumerable<LookupData> 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();
}
Expand All @@ -110,7 +116,7 @@ private string AddForeignKeys(IEnumerable<EnumReference> refs)
private string PopulateLookups(IEnumerable<LookupData> 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));
Expand All @@ -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(@"
Expand All @@ -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
;"
Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions EfEnumToLookupTests/Tests/EnumParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public void ReadsByteEnum()


[Test]
public void ReadsDecoratedName()
public void ReadsDecoratedDescription()
{
// arrange
var parser = new EnumParser { SplitWords = true };
Expand All @@ -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
Expand Down
51 changes: 50 additions & 1 deletion ExampleUsage/EnumExample.cs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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<LookupRow>("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<LookupRow>("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);
}
}
}

/// <summary>
Expand Down Expand Up @@ -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).
Expand All @@ -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; }
}
}

0 comments on commit b3263f5

Please sign in to comment.