解决EF没有生成字段和表说明
找了很多资料,终于找到一篇真正能解决ef生成字段说明,注释的文章,收藏不了,于是转载
本文章为转载,原文地址
项目中使用了EF框架,使用的是Database-First方式,因为数据库已经存在,所以采用Database-First方式,ef生成实体类的时候,发现微软没有自动生成表字段和表说明,在网上找了些资料,由于都不太全,倒腾了近2个小时,所以根据网上的帖子为基础,写得更详细一点,让初学者更容易明白和少走弯路。网上也有一些自动生成的软件,可以自动生成,但是更新数据库需要重新生成,有点麻烦,所有根据T4模板解决
第一步:
下载GetSummery.ttinclude文件,链接失效,现在贴出文件内容,自己重命名为这个文件就好啦,GetSummery.ttinclude是模板文件,为了实现EF框架添加数据库自动生成实体注释。
<#@ template language="C#v3.5" hostspecific="True" #>
<#@ assembly name="EnvDTE" #>
<#@ assembly name="System.Data" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="System.Configuration" #>
<#@ assembly name="System.Windows.Forms" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Data" #>
<#@ import namespace="System.Data.SqlClient" #>
<#@ import namespace="System.Data.Common" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Globalization" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#@ import namespace="System.Configuration" #>
<#@ import namespace="System.Windows.Forms" #>
<#+string ConnectionStringName = "MyConn";
string Namespace = "";
string RepoName = "";
string ClassPrefix = "";
string ClassSuffix = "";
string SchemaName = null;
bool IncludeViews = false;
bool GenerateOperations = false;
bool GenerateCommon = true;
bool GeneratePocos = true;
bool TrackModifiedColumns = false;static Regex rxCleanUp = new Regex(@"[^\w\d_]", RegexOptions.Compiled);static Func CleanUp = (str) =>
{str = rxCleanUp.Replace(str, "_");if (char.IsDigit(str[0])) str = "_" + str;return str;
};string GetConnectionString(ref string connectionStringName, out string providerName)
{var _CurrentProject = GetCurrentProject();providerName=null;string result="";ExeConfigurationFileMap configFile = new ExeConfigurationFileMap();configFile.ExeConfigFilename = GetConfigPath();if (string.IsNullOrEmpty(configFile.ExeConfigFilename))throw new ArgumentNullException("The project does not contain App.config or Web.config file.");var config = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(configFile, ConfigurationUserLevel.None);var connSection=config.ConnectionStrings;//if the connectionString is empty - which is the defauls//look for count-1 - this is the last connection string//and takes into account AppServices and LocalSqlServerif(string.IsNullOrEmpty(connectionStringName)){if(connSection.ConnectionStrings.Count>1){connectionStringName = connSection.ConnectionStrings[connSection.ConnectionStrings.Count-1].Name;result=connSection.ConnectionStrings[connSection.ConnectionStrings.Count-1].ConnectionString;providerName=connSection.ConnectionStrings[connSection.ConnectionStrings.Count-1].ProviderName;} }else{try{result=connSection.ConnectionStrings[connectionStringName].ConnectionString;providerName=connSection.ConnectionStrings[connectionStringName].ProviderName;}catch{result="There is no connection string name called '"+connectionStringName+"'";}}// if (String.IsNullOrEmpty(providerName))
// providerName="System.Data.SqlClient";return result;
}string _connectionString="";
string _providerName="";void InitConnectionString()
{if(String.IsNullOrEmpty(_connectionString)){_connectionString=GetConnectionString(ref ConnectionStringName, out _providerName);if(_connectionString.Contains("|DataDirectory|")){//have to replace itstring dataFilePath=GetDataDirectory();_connectionString=_connectionString.Replace("|DataDirectory|",dataFilePath);} }
}public string ConnectionString
{get {InitConnectionString();return _connectionString;}
}public string ProviderName
{get {InitConnectionString();return _providerName;}
}public EnvDTE.Project GetCurrentProject() {IServiceProvider _ServiceProvider = (IServiceProvider)Host;if (_ServiceProvider == null)throw new Exception("Host property returned unexpected value (null)");EnvDTE.DTE dte = (EnvDTE.DTE)_ServiceProvider.GetService(typeof(EnvDTE.DTE));if (dte == null)throw new Exception("Unable to retrieve EnvDTE.DTE");Array activeSolutionProjects = (Array)dte.ActiveSolutionProjects;if (activeSolutionProjects == null)throw new Exception("DTE.ActiveSolutionProjects returned null");EnvDTE.Project dteProject = (EnvDTE.Project)activeSolutionProjects.GetValue(0);if (dteProject == null)throw new Exception("DTE.ActiveSolutionProjects[0] returned null");return dteProject;}private string GetProjectPath()
{EnvDTE.Project project = GetCurrentProject();System.IO.FileInfo info = new System.IO.FileInfo(project.FullName);return info.Directory.FullName;
}private string GetConfigPath()
{EnvDTE.Project project = GetCurrentProject();foreach (EnvDTE.ProjectItem item in project.ProjectItems){// if it is the app.config file, then open it upif (item.Name.Equals("App.config",StringComparison.InvariantCultureIgnoreCase) || item.Name.Equals("Web.config",StringComparison.InvariantCultureIgnoreCase))return GetProjectPath() + "\\" + item.Name;}return String.Empty;
}public string GetDataDirectory()
{EnvDTE.Project project=GetCurrentProject();return System.IO.Path.GetDirectoryName(project.FileName)+"\\App_Data\\";
}static string zap_password(string connectionString)
{var rx = new Regex("password=.*;", RegexOptions.Singleline | RegexOptions.Multiline | RegexOptions.IgnoreCase);return rx.Replace(connectionString, "password=**zapped**;");
}//得到列说明
string getColumnSummery(string tablename,string columnname)
{InitConnectionString();DbProviderFactory _factory;_factory = DbProviderFactories.GetFactory(ProviderName);using(var conn=_factory.CreateConnection()){conn.ConnectionString=ConnectionString; conn.Open();//string sql=@"SELECT TOP 1 ex.value FROM sys.columns c LEFT OUTER JOIN sys.extended_properties ex ON ex.major_id = c.object_id AND ex.minor_id = c.column_id AND ex.name = 'MS_Description' left outer join systypes t on c.system_type_id=t.xtype WHERE OBJECTPROPERTY(c.object_id, 'IsMsShipped')=0 ";string sql=@"SELECT TOP 1 ex.value FROM sys.columns c LEFT OUTER JOIN sys.extended_properties ex ON ex.major_id = c.object_id AND ex.minor_id = c.column_id AND ex.name = 'MS_Description' left outer join systypes t on c.system_type_id=t.xtype WHERE OBJECTPROPERTY(c.object_id, 'IsMsShipped')=0 AND OBJECT_NAME(c.object_id)=@tablename AND c.name=@columname ";using (var cmd=_factory.CreateCommand()){cmd.Connection=conn;cmd.CommandText=sql;var p = cmd.CreateParameter();p.ParameterName = "@tablename";p.Value=tablename;cmd.Parameters.Add(p);p = cmd.CreateParameter();p.ParameterName = "@columname";p.Value=columnname;cmd.Parameters.Add(p);var result=cmd.ExecuteScalar();conn.Close();if(result!=null)return result.ToString(); elsereturn ProviderName;} return "";}}//得到表说明备注
string getTableSummery(string tablename)
{InitConnectionString();DbProviderFactory _factory;_factory = DbProviderFactories.GetFactory(ProviderName);using(var conn=_factory.CreateConnection()){conn.ConnectionString=ConnectionString; conn.Open();//string sql=@"SELECT TOP 1 ex.value FROM sys.columns c LEFT OUTER JOIN sys.extended_properties ex ON ex.major_id = c.object_id AND ex.minor_id = c.column_id AND ex.name = 'MS_Description' left outer join systypes t on c.system_type_id=t.xtype WHERE OBJECTPROPERTY(c.object_id, 'IsMsShipped')=0 ";string sql=@"SELECT TOP 1 TableSumary FROM (select c.Name AS TableName,isnull(f.[value],'') AS TableSumary from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id inner join sys.objects c on a.object_id=c.object_id and c.Type='U' left join syscomments d on a.default_object_id=d.ID left join sys.extended_properties e on e.major_id=c.object_id and e.minor_id=a.Column_id and e.class=1 left join sys.extended_properties f on f.major_id=c.object_id and f.minor_id=0 and f.class=1) AS Mytb WHERE TableName=@tablename ";using (var cmd=_factory.CreateCommand()){cmd.Connection=conn;cmd.CommandText=sql;var p = cmd.CreateParameter();p.ParameterName = "@tablename";p.Value=tablename;cmd.Parameters.Add(p);var result=cmd.ExecuteScalar();conn.Close();if(result!=null)return result.ToString(); elsereturn ProviderName;} return "";}}///
/// Summary for the Inflector class
///
public static class Inflector {private static readonly List _plurals = new List();private static readonly List _singulars = new List();private static readonly List _uncountables = new List();/// /// Initializes the class./// static Inflector() {AddPluralRule("$", "s");AddPluralRule("s$", "s");AddPluralRule("(ax|test)is$", "$1es");AddPluralRule("(octop|vir)us$", "$1i");AddPluralRule("(alias|status)$", "$1es");AddPluralRule("(bu)s$", "$1ses");AddPluralRule("(buffal|tomat)o$", "$1oes");AddPluralRule("([ti])um$", "$1a");AddPluralRule("sis$", "ses");AddPluralRule("(?:([^f])fe|([lr])f)$", "$1$2ves");AddPluralRule("(hive)$", "$1s");AddPluralRule("([^aeiouy]|qu)y$", "$1ies");AddPluralRule("(x|ch|ss|sh)$", "$1es");AddPluralRule("(matr|vert|ind)ix|ex$", "$1ices");AddPluralRule("([m|l])ouse$", "$1ice");AddPluralRule("^(ox)$", "$1en");AddPluralRule("(quiz)$", "$1zes");AddSingularRule("s$", String.Empty);AddSingularRule("ss$", "ss");AddSingularRule("(n)ews$", "$1ews");AddSingularRule("([ti])a$", "$1um");AddSingularRule("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "$1$2sis");AddSingularRule("(^analy)ses$", "$1sis");AddSingularRule("([^f])ves$", "$1fe");AddSingularRule("(hive)s$", "$1");AddSingularRule("(tive)s$", "$1");AddSingularRule("([lr])ves$", "$1f");AddSingularRule("([^aeiouy]|qu)ies$", "$1y");AddSingularRule("(s)eries$", "$1eries");AddSingularRule("(m)ovies$", "$1ovie");AddSingularRule("(x|ch|ss|sh)es$", "$1");AddSingularRule("([m|l])ice$", "$1ouse");AddSingularRule("(bus)es$", "$1");AddSingularRule("(o)es$", "$1");AddSingularRule("(shoe)s$", "$1");AddSingularRule("(cris|ax|test)es$", "$1is");AddSingularRule("(octop|vir)i$", "$1us");AddSingularRule("(alias|status)$", "$1");AddSingularRule("(alias|status)es$", "$1");AddSingularRule("^(ox)en", "$1");AddSingularRule("(vert|ind)ices$", "$1ex");AddSingularRule("(matr)ices$", "$1ix");AddSingularRule("(quiz)zes$", "$1");AddIrregularRule("person", "people");AddIrregularRule("man", "men");AddIrregularRule("child", "children");AddIrregularRule("sex", "sexes");AddIrregularRule("tax", "taxes");AddIrregularRule("move", "moves");AddUnknownCountRule("equipment");AddUnknownCountRule("information");AddUnknownCountRule("rice");AddUnknownCountRule("money");AddUnknownCountRule("species");AddUnknownCountRule("series");AddUnknownCountRule("fish");AddUnknownCountRule("sheep");}/// /// Adds the irregular rule./// /// The singular./// The plural.private static void AddIrregularRule(string singular, string plural) {AddPluralRule(String.Concat("(", singular[0], ")", singular.Substring(1), "$"), String.Concat("$1", plural.Substring(1)));AddSingularRule(String.Concat("(", plural[0], ")", plural.Substring(1), "$"), String.Concat("$1", singular.Substring(1)));}/// /// Adds the unknown count rule./// /// The word.private static void AddUnknownCountRule(string word) {_uncountables.Add(word.ToLower());}/// /// Adds the plural rule./// /// The rule./// The replacement.private static void AddPluralRule(string rule, string replacement) {_plurals.Add(new InflectorRule(rule, replacement));}/// /// Adds the singular rule./// /// The rule./// The replacement.private static void AddSingularRule(string rule, string replacement) {_singulars.Add(new InflectorRule(rule, replacement));}/// /// Makes the plural./// /// The word./// public static string MakePlural(string word) {return ApplyRules(_plurals, word);}/// /// Makes the singular./// /// The word./// public static string MakeSingular(string word) {return ApplyRules(_singulars, word);}/// /// Applies the rules./// /// The rules./// The word./// private static string ApplyRules(IList rules, string word) {string result = word;if (!_uncountables.Contains(word.ToLower())) {for (int i = rules.Count - 1; i >= 0; i--) {string currentPass = rules[i].Apply(word);if (currentPass != null) {result = currentPass;break;}}}return result;}/// /// Converts the string to title case./// /// The word./// public static string ToTitleCase(string word) {return Regex.Replace(ToHumanCase(AddUnderscores(word)), @"\b([a-z])",delegate(Match match) { return match.Captures[0].Value.ToUpper(); });}/// /// Converts the string to human case./// /// The lowercase and underscored word./// public static string ToHumanCase(string lowercaseAndUnderscoredWord) {return MakeInitialCaps(Regex.Replace(lowercaseAndUnderscoredWord, @"_", " "));}/// /// Adds the underscores./// /// The pascal cased word./// public static string AddUnderscores(string pascalCasedWord) {return Regex.Replace(Regex.Replace(Regex.Replace(pascalCasedWord, @"([A-Z]+)([A-Z][a-z])", "$1_$2"), @"([a-z\d])([A-Z])", "$1_$2"), @"[-\s]", "_").ToLower();}/// /// Makes the initial caps./// /// The word./// public static string MakeInitialCaps(string word) {return String.Concat(word.Substring(0, 1).ToUpper(), word.Substring(1).ToLower());}/// /// Makes the initial lower case./// /// The word./// public static string MakeInitialLowerCase(string word) {return String.Concat(word.Substring(0, 1).ToLower(), word.Substring(1));}/// /// Determine whether the passed string is numeric, by attempting to parse it to a double/// /// The string to evaluated for numeric conversion/// /// true if the string can be converted to a number; otherwise, false ./// public static bool IsStringNumeric(string str) {double result;return (double.TryParse(str, NumberStyles.Float, NumberFormatInfo.CurrentInfo, out result));}/// /// Adds the ordinal suffix./// /// The number./// public static string AddOrdinalSuffix(string number) {if (IsStringNumeric(number)) {int n = int.Parse(number);int nMod100 = n % 100;if (nMod100 >= 11 && nMod100 <= 13)return String.Concat(number, "th");switch (n % 10) {case 1:return String.Concat(number, "st");case 2:return String.Concat(number, "nd");case 3:return String.Concat(number, "rd");default:return String.Concat(number, "th");}}return number;}/// /// Converts the underscores to dashes./// /// The underscored word./// public static string ConvertUnderscoresToDashes(string underscoredWord) {return underscoredWord.Replace('_', '-');}#region Nested type: InflectorRule/// /// Summary for the InflectorRule class/// private class InflectorRule {/// /// /// public readonly Regex regex;/// /// /// public readonly string replacement;/// /// Initializes a new instance of the class./// /// The regex pattern./// The replacement text.public InflectorRule(string regexPattern, string replacementText) {regex = new Regex(regexPattern, RegexOptions.IgnoreCase);replacement = replacementText;}/// /// Applies the specified word./// /// The word./// public string Apply(string word) {if (!regex.IsMatch(word))return null;string replace = regex.Replace(word, replacement);if (word == word.ToUpper())replace = replace.ToUpper();return replace;}}#endregion
}#>
第二步:
把GetSummery.ttinclude文件放到Model1.edmx同一级目录,当然也可以放到其他路径,为了方便放到同一级目录。
第三步:打开GetSummery.ttinclude文件,修改GetSummery.ttinclude连接数据库的字符串改为"ConnStr",prioviderName属性必须要有哦。
第四步:打开EF项目文件所在的tt文件
第五步:在tt头部添加 <#@ include file="GetSummery.ttinclude" #>
第六步:加载自定义TT文件用来获取数据库表备注和字段备注说明
在TT文件里搜索:<#=codeStringGenerator.UsingDirectives(inHeader: false)#>
把代码添加<#=codeStringGenerator.UsingDirectives(inHeader: false)#>到下面
///
/// <#= getTableSummery(code.Escape(entity)) #>
///
如图所示:
第七步:第二次搜索:<#=codeStringGenerator.Property(edmProperty)#>, 在它上方插入代码:
///
/// <#= getColumnSummery(code.Escape(entity),code.Escape(edmProperty)) #>
///
如图所示:
第八步:保存TT文件,它会自动更新数据库里的各个实体
效果如图:
操作完毕!
转载于:https://www.cnblogs.com/CoderLinkf/p/8922110.html
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
