解决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<string, string> 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 LocalSqlServer
    if(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 it
			string 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 up
        if (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();    
			else
				return 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();    
			else
				return ProviderName;
		}	    
          
		return "";
	
	}
	     
}





/// <summary>
/// Summary for the Inflector class
/// </summary>
public static class Inflector {
    private static readonly List<InflectorRule> _plurals = new List<InflectorRule>();
    private static readonly List<InflectorRule> _singulars = new List<InflectorRule>();
    private static readonly List<string> _uncountables = new List<string>();

    /// <summary>
    /// Initializes the <see cref="Inflector"/> class.
    /// </summary>
    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");
    }

    /// <summary>
    /// Adds the irregular rule.
    /// </summary>
    /// <param name="singular">The singular.</param>
    /// <param name="plural">The plural.</param>
    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)));
    }

    /// <summary>
    /// Adds the unknown count rule.
    /// </summary>
    /// <param name="word">The word.</param>
    private static void AddUnknownCountRule(string word) {
        _uncountables.Add(word.ToLower());
    }

    /// <summary>
    /// Adds the plural rule.
    /// </summary>
    /// <param name="rule">The rule.</param>
    /// <param name="replacement">The replacement.</param>
    private static void AddPluralRule(string rule, string replacement) {
        _plurals.Add(new InflectorRule(rule, replacement));
    }

    /// <summary>
    /// Adds the singular rule.
    /// </summary>
    /// <param name="rule">The rule.</param>
    /// <param name="replacement">The replacement.</param>
    private static void AddSingularRule(string rule, string replacement) {
        _singulars.Add(new InflectorRule(rule, replacement));
    }

    /// <summary>
    /// Makes the plural.
    /// </summary>
    /// <param name="word">The word.</param>
    /// <returns></returns>
    public static string MakePlural(string word) {
        return ApplyRules(_plurals, word);
    }

    /// <summary>
    /// Makes the singular.
    /// </summary>
    /// <param name="word">The word.</param>
    /// <returns></returns>
    public static string MakeSingular(string word) {
        return ApplyRules(_singulars, word);
    }

    /// <summary>
    /// Applies the rules.
    /// </summary>
    /// <param name="rules">The rules.</param>
    /// <param name="word">The word.</param>
    /// <returns></returns>
    private static string ApplyRules(IList<InflectorRule> 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;
    }

    /// <summary>
    /// Converts the string to title case.
    /// </summary>
    /// <param name="word">The word.</param>
    /// <returns></returns>
    public static string ToTitleCase(string word) {
        return Regex.Replace(ToHumanCase(AddUnderscores(word)), @"\b([a-z])",
            delegate(Match match) { return match.Captures[0].Value.ToUpper(); });
    }

    /// <summary>
    /// Converts the string to human case.
    /// </summary>
    /// <param name="lowercaseAndUnderscoredWord">The lowercase and underscored word.</param>
    /// <returns></returns>
    public static string ToHumanCase(string lowercaseAndUnderscoredWord) {
        return MakeInitialCaps(Regex.Replace(lowercaseAndUnderscoredWord, @"_", " "));
    }


    /// <summary>
    /// Adds the underscores.
    /// </summary>
    /// <param name="pascalCasedWord">The pascal cased word.</param>
    /// <returns></returns>
    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();
    }

    /// <summary>
    /// Makes the initial caps.
    /// </summary>
    /// <param name="word">The word.</param>
    /// <returns></returns>
    public static string MakeInitialCaps(string word) {
        return String.Concat(word.Substring(0, 1).ToUpper(), word.Substring(1).ToLower());
    }

    /// <summary>
    /// Makes the initial lower case.
    /// </summary>
    /// <param name="word">The word.</param>
    /// <returns></returns>
    public static string MakeInitialLowerCase(string word) {
        return String.Concat(word.Substring(0, 1).ToLower(), word.Substring(1));
    }


    /// <summary>
    /// Determine whether the passed string is numeric, by attempting to parse it to a double
    /// </summary>
    /// <param name="str">The string to evaluated for numeric conversion</param>
    /// <returns>
    /// 	<c>true</c> if the string can be converted to a number; otherwise, <c>false</c>.
    /// </returns>
    public static bool IsStringNumeric(string str) {
        double result;
        return (double.TryParse(str, NumberStyles.Float, NumberFormatInfo.CurrentInfo, out result));
    }

    /// <summary>
    /// Adds the ordinal suffix.
    /// </summary>
    /// <param name="number">The number.</param>
    /// <returns></returns>
    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;
    }

    /// <summary>
    /// Converts the underscores to dashes.
    /// </summary>
    /// <param name="underscoredWord">The underscored word.</param>
    /// <returns></returns>
    public static string ConvertUnderscoresToDashes(string underscoredWord) {
        return underscoredWord.Replace('_', '-');
    }


    #region Nested type: InflectorRule

    /// <summary>
    /// Summary for the InflectorRule class
    /// </summary>
    private class InflectorRule {
        /// <summary>
        /// 
        /// </summary>
        public readonly Regex regex;

        /// <summary>
        /// 
        /// </summary>
        public readonly string replacement;

        /// <summary>
        /// Initializes a new instance of the <see cref="InflectorRule"/> class.
        /// </summary>
        /// <param name="regexPattern">The regex pattern.</param>
        /// <param name="replacementText">The replacement text.</param>
        public InflectorRule(string regexPattern, string replacementText) {
            regex = new Regex(regexPattern, RegexOptions.IgnoreCase);
            replacement = replacementText;
        }

        /// <summary>
        /// Applies the specified word.
        /// </summary>
        /// <param name="word">The word.</param>
        /// <returns></returns>
        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)#>到下面 

/// <summary>
/// <#= getTableSummery(code.Escape(entity)) #>
/// </summary>

 

如图所示:

 

第七步:第二次搜索:<#=codeStringGenerator.Property(edmProperty)#>, 在它上方插入代码:

/// <summary>
/// <#= getColumnSummery(code.Escape(entity),code.Escape(edmProperty)) #>
/// </summary>

 

如图所示:

 

第八步:保存TT文件,它会自动更新数据库里的各个实体

效果如图:

 

操作完毕!

 

posted @ 2018-04-23 22:02  CoderLinkf  阅读(1324)  评论(0编辑  收藏  举报