एक डीबी पहले दृष्टिकोण प्रत्येक enum जहां ईद स्तंभ नाम से मेल खाता तालिका नाम के लिए एक सुसंगत तालिका बनाने के द्वारा इस्तेमाल किया जा सकता। विदेशी कुंजी बाधाओं और विचारों में अनुकूल कॉलम का समर्थन करने के लिए डेटाबेस के भीतर enum मान उपलब्ध कराने के लिए फायदेमंद है। वर्तमान में हम कई संस्करण वाले डेटाबेसों में बिखरे हुए ~ 100 enum प्रकारों का समर्थन कर रहे हैं।
कोड-प्रथम वरीयता के लिए, नीचे दिखाए गए टी 4 रणनीति को शायद डेटाबेस में लिखने के लिए उलट दिया जा सकता है।
create table SomeSchema.SomeEnumType (
SomeEnumTypeId smallint NOT NULL primary key,
Name varchar(100) not null,
Description nvarchar(1000),
ModifiedUtc datetime2(7) default(sysutcdatetime()),
CreatedUtc datetime2(7) default(sysutcdatetime()),
);
प्रत्येक तालिका को T4 template (*.tt) script का उपयोग करके सी # में आयात किया जा सकता है।
- "गणना परियोजना" बनाएं। नीचे दिखाए गए .tt फ़ाइल जोड़ें।
- प्रत्येक डेटाबेस स्कीमा नाम के लिए उप-फ़ोल्डर बनाएं।
- प्रत्येक enum प्रकार के लिए, एक फ़ाइल बनाएं जिसका नाम SchemaName.TableName.tt है। फ़ाइल सामग्री हमेशा एक ही एकल लाइन कर रहे हैं: < # @ फ़ाइल को शामिल = ".. \ EnumGenerator.ttinclude" #>
- फिर बनाने के लिए/enums अद्यतन करते हैं, सही 1 या अधिक फ़ाइलों पर क्लिक करें और "रन कस्टम टूल "(हमारे पास अभी तक ऑटो अपडेट नहीं है)। यह परियोजना के लिए जोड़ देगा/अद्यतन एक .cs फ़ाइल:
using System.CodeDom.Compiler;
namespace TheCompanyNamespace.Enumerations.Config
{
[GeneratedCode("Auto Enum from DB Generator", "10")]
public enum DatabasePushJobState
{
Undefined = 0,
Created = 1,
}
public partial class EnumDescription
{
public static string Description(DatabasePushJobState enumeration)
{
string description = "Unknown";
switch (enumeration)
{
case DatabasePushJobState.Undefined:
description = "Undefined";
break;
case DatabasePushJobState.Created:
description = "Created";
break;
}
return description;
}
}
// select DatabasePushJobStateId, Name, coalesce(Description,Name) as Description
// from TheDefaultDatabase.[SchName].[DatabasePushJobState]
// where 1=1 order by DatabasePushJobStateId
}
और अंत में, कुछ हद तक ऐंठा हुआ टी -4 लिपि (कई समाधानों से सरलीकृत)। इसे आपके पर्यावरण में अनुकूलित करने की आवश्यकता होगी। एक डीबग ध्वज सी # में संदेशों को आउटपुट कर सकता है। .tt फ़ाइल पर राइट क्लिक करते समय "डीबग टी 4 टेम्पलेट" विकल्प भी है। EnumGenerator.ttinclude:
<#@ template debug="true" hostSpecific="true" #>
<#@ output extension=".generated.cs" #>
<#@ Assembly Name="EnvDTE" #>
<#@ Assembly Name="System.Core" #>
<#@ Assembly Name="System.Data" #>
<#@ assembly name="$(TargetPath)" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Data" #>
<#@ import namespace="System.Data.SqlClient" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#
bool doDebug = false; // include debug statements to appear in generated output
string schemaTableName = Path.GetFileNameWithoutExtension(Host.TemplateFile);
string schema = schemaTableName.Split('.')[0];
string tableName = schemaTableName.Split('.')[1];
string path = Path.GetDirectoryName(Host.TemplateFile);
string enumName = tableName;
string columnId = enumName + "Id";
string columnName = "Name";
string columnDescription = "Description";
string currentVersion = CompanyNamespace.Enumerations.Constants.Constants.DefaultDatabaseVersionSuffix;
// Determine Database Name using Schema Name
//
Dictionary<string, string> schemaToDatabaseNameMap = new Dictionary<string, string> {
{ "Cfg", "SomeDbName" + currentVersion },
{ "Common", "SomeOtherDbName" + currentVersion }
// etc.
};
string databaseName;
if (!schemaToDatabaseNameMap.TryGetValue(schema, out databaseName))
{
databaseName = "TheDefaultDatabase"; // default if not in map
}
string connectionString = @"Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=" + databaseName + @";Data Source=Machine\Instance";
schema = "[" + schema + "]";
tableName = "[" + tableName + "]";
string whereConstraint = "1=1"; // adjust if needed for specific tables
// Get containing project
IServiceProvider serviceProvider = (IServiceProvider)Host;
DTE dte = (DTE)serviceProvider.GetService(typeof(DTE));
Project project = dte.Solution.FindProjectItem(Host.TemplateFile).ContainingProject;
#>
using System;
using System.CodeDom.Compiler;
namespace <#= project.Properties.Item("DefaultNamespace").Value #><#= Path.GetDirectoryName(Host.TemplateFile).Remove(0, Path.GetDirectoryName(project.FileName).Length).Replace("\\", ".") #>
{
/// <summary>
/// Auto-generated Enumeration from Source Table <#= databaseName + "." + schema + "." + tableName #>. Refer to end of file for SQL.
/// Please do not modify, your changes will be lost!
/// </summary>
[GeneratedCode("Auto Enum from DB Generator", "10")]
public enum <#= enumName #>
{
<#
SqlConnection conn = new SqlConnection(connectionString);
// Description is optional, uses name if null
string command = string.Format(
"select {0}, {1}, coalesce({2},{1}) as {2}" + "\n from {3}.{4}.{5}\n where {6} order by {0}",
columnId, // 0
columnName, // 1
columnDescription, // 2
databaseName, // 3
schema, // 4
tableName, // 5
whereConstraint); // 6
#><#= DebugCommand(databaseName, command, doDebug) #><#
SqlCommand comm = new SqlCommand(command, conn);
conn.Open();
SqlDataReader reader = comm.ExecuteReader();
bool loop = reader.Read();
while(loop)
{
#> /// <summary>
/// <#= reader[columnDescription] #>
/// </summary>
<#= Pascalize(reader[columnName]) #> = <#= reader[columnId] #><# loop = reader.Read(); #><#= loop ? ",\r\n" : string.Empty #>
<#
}
#> }
/// <summary>
/// A helper class to return the Description for each enumeration value
/// </summary>
public partial class EnumDescription
{
public static string Description(<#= enumName #> enumeration)
{
string description = "Unknown";
switch (enumeration)
{<#
conn.Close();
conn.Open();
reader = comm.ExecuteReader();
loop = reader.Read();
while(loop)
{#>
case <#= enumName #>.<#= Pascalize(reader[columnName]) #>:
description = "<#= reader[columnDescription].ToString().Replace("\"", "\\\"") #>";
break;
<# loop = reader.Read(); #>
<#
}
conn.Close();
#>
}
return description;
}
}
/*
<#= command.Replace("\n", "\r\n ") #>
*/
}
<#+
private string Pascalize(object value)
{
Regex rxStartsWithKeyWord = new Regex(@"^[0-9]|^abstract$|^as$|^base$|^bool$|^break$|^byte$|^case$|^catch$|^char$|^checked$|^class$|^const$|^continue$|^decimal$|^default$|^delegate$|^do$|^double$|^else$|^enum$|^event$|^explicit$|^extern$|^$false|^finally$|^fixed$|^float$|^for$|^foreach$|^goto$|^if$|^implicit$|^in$|^int$|^interface$|^internal$|^is$|^lock$|^long$|^namespace$|^new$|^null$|^object$|^operator$|^out$|^overrride$|^params$|^private$|^protected$|^public$|^readonly$|^ref$|^return$|^sbyte$|^sealed$|^short$|^sizeof$|^stackalloc$|^static$|^string$|^struct$|^switch$|^this$|^thorw$|^true$|^try$|^typeof$|^uint$|^ulong$|^unchecked$|^unsafe$|^ushort$|^using$|^virtual$|^volatile$|^void$|^while$", RegexOptions.Compiled);
Regex rx = new Regex(@"(?:[^a-zA-Z0-9]*)(?<first>[a-zA-Z0-9])(?<reminder>[a-zA-Z0-9]*)(?:[^a-zA-Z0-9]*)");
string rawName = rx.Replace(value.ToString(), m => m.Groups["first"].ToString().ToUpper() + m.Groups["reminder"].ToString());
if (rxStartsWithKeyWord.Match(rawName).Success)
rawName = "_" + rawName;
return rawName;
}
private string DebugCommand(string databaseName, string command, bool doDebug)
{
return doDebug
? " // use " + databaseName + "; " + command + ";\r\n\r\n"
: "";
}
#>
उम्मीद है कि इकाई की रूपरेखा किसी दिन इन उत्तरों का एक संयोजन रिकॉर्ड और डेटाबेस मूल्यों की मिररिंग भीतर सी # enum मजबूत टाइपिंग की पेशकश करने का समर्थन करेंगे।
+1 मुझे इस राय में दिलचस्पी है कि इस तरह की चीज को अलग-अलग तालिकाओं और एफके बाधा के साथ लागू किया जाना चाहिए या किसी के पास कोई नियमित बाधा है? –
@ मार्टिन उत्तर देने की योजना नहीं बना रहा क्योंकि यह काफी व्यक्तिपरक होगा, लेकिन ओएलटीपी/ओडीएस के लिए मैं एफके बाधा के साथ अलग-अलग तालिकाओं का उपयोग करूंगा। एक डीएसएस रिपोर्टिंग समाधान के लिए, मैं अन्य तथ्यों के साथ रिपोर्टिंग तालिका में enum के प्रतीकात्मक नाम (या विवरण) को denormalize और स्टोर करेगा। –