-
Notifications
You must be signed in to change notification settings - Fork 226
Settings.Enumerations
Turns the rows of a lookup table into a real C# enum, and the five settings that control it.
| Setting | Type | Role |
|---|---|---|
Settings.Enumerations |
List<EnumerationSettings> |
Declares which tables become enums |
Settings.AddEnum |
Action<Table> |
Decides programmatically, per table |
Settings.UpdateEnum |
Action<Enumeration> |
Attributes on the generated enum |
Settings.UpdateEnumMember |
Action<EnumerationMember> |
Attributes on each member |
Settings.AddEnumDefinitions |
Action<List<EnumDefinition>> |
Replaces a column's type with an enum |
Settings.UsePascalCaseForEnumMembers |
bool |
Whether member names are PascalCased |
All apply to EF 6 and EF Core, on every database, and all are in Database.tt.
They are easy to confuse.
Generating an enum from table rows is Settings.Enumerations. A DaysOfWeek table with a TypeId and a
TypeName column becomes:
public enum DaysOfWeek
{
Monday = 1,
Tuesday = 2,
...
}Replacing a column's type with an enum is Settings.AddEnumDefinitions. An OrderHeader.OrderStatus
column typed tinyint becomes public OrderStatusType OrderStatus { get; set; }. The enum can be one you
generated, or one you wrote by hand.
You often want both: generate the enum from the lookup table, then use it as the type of the foreign key column that points at it.
Settings.Enumerations = new List<EnumerationSettings>
{
new EnumerationSettings
{
Name = "DaysOfWeek", // The enum to generate
Table = "EnumTest.DaysOfWeek", // Schema.TableName
NameField = "TypeName", // Column holding the member names
ValueField = "TypeId" // Column holding the values
}
};EnumerationSettings also has:
| Field | Purpose |
|---|---|
GroupField |
For a table holding several enums. Put {GroupField} in Name, e.g. "{GroupField}Enum"
|
DescriptionField |
A column whose text becomes a [Description("...")] attribute on each member |
GenerateDescriptionFromName |
Generates a [Description] from the member name where DescriptionField gives nothing |
AllFields |
Every column of the row, for use in UpdateEnumMember
|
Full worked examples on Enum Generation from Table Data.
Rather than listing tables by hand, decide by rule:
Settings.AddEnum = delegate(Table table)
{
if (table.HasPrimaryKey &&
table.PrimaryKeys.Count() == 1 &&
table.NameHumanCase.EndsWith("Enum", StringComparison.InvariantCultureIgnoreCase))
{
Settings.Enumerations.Add(new EnumerationSettings
{
Name = table.NameHumanCase.Replace("Enum", "") + "Enum",
Table = table.Schema.DbName + "." + table.DbName,
NameField = table.Columns.First(x => x.PropertyType == "string").DbName,
ValueField = table.PrimaryKeys.Single().DbName
});
table.RemoveTable = true; // Do not also generate a POCO for it
}
};Settings.ElementsToGenerate must contain both Elements.Poco and Elements.Enum for this to work.
Settings.UpdateEnum = e => e.EnumAttributes.Add("[DataContract]");
Settings.UpdateEnumMember = m =>
{
m.Attributes.Add("[EnumMember]");
// AllValues holds every column of the source row
if (m.AllValues.ContainsKey("SortOrder"))
m.Attributes.Add(string.Format("[Display(Order = {0})]", m.AllValues["SortOrder"]));
};Default true. Member names come from data, and data is rarely written in C# style - "IN PROGRESS",
"on_hold". With this on they become InProgress and OnHold; with it off they are used as-is, with illegal
characters stripped.
It is separate from Settings.UsePascalCase precisely because you might want your
tables PascalCased and your enum members left exactly as the data has them.
Enum generation reads rows, so it needs a live database. The efrpg tool is invoked a second time to
select the values. That is the only part of generation that reads data rather than schema, and it will not
work against a database you can only read metadata from.
Set table.RemoveTable = true or you get both. A table that becomes an enum will otherwise also generate
a POCO and a DbSet, which is almost never wanted.
Table is "Schema.TableName", one string. Omitting the schema works only for the default schema.
Duplicate or illegal member names break the build. Two rows whose names PascalCase to the same identifier,
or a name that is a C# keyword, produce an enum that does not compile. Data changes and your build breaks -
which is an argument for DescriptionField over creative naming.
Values must be whole numbers. ValueField has to be an integral column. A string value field works only
where the strings parse as integers.
AddEnumDefinitions needs Settings.ApplyEnumTypeReplacement to be called. The shipped
Settings.UpdateColumn calls it at the end. Replace UpdateColumn and drop that
call, and the type replacement silently stops happening.
- Enum Generation from Table Data - the full walkthrough with generated output
-
Settings.UpdateColumn - where
ApplyEnumTypeReplacementis called -
Settings.ElementsToGenerate -
Elements.Enum - Settings Reference
- Home
- Compared with the Microsoft scaffolder
- Connection strings
- JetBrains Rider
- Upgrading from v3 to v4
- Saving .tt does nothing
- Settings A-Z - every setting, with a page each
- Common Settings Types Explained
- Settings Callbacks
- Settings runtime values and helpers
- Filtering
- Full Control Over the Generated Code
- Enum Generation from Table Data
- Owned Entities
- JSON column support
- Global Query Filters
- Extended Property Names Feature
- Partial Properties
- File-Scoped Namespaces
- Data Annotations
- Spatial Types
- HierarchyId
- RowVersion and TimeStamp columns
- Lazy Loading
- Stored proc result sets