zoukankan      html  css  js  c++  java
  • 解决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(@"[^wd_]", 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)), @"([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-zd])([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文件,它会自动更新数据库里的各个实体

    效果如图:

    操作完毕!

     

  • 相关阅读:
    学生管理系统简化版
    图形用户界面编程——事件驱动编程
    图形界面编程
    集合框架
    多线程编程
    反射
    相关类
    异常(4.13)
    接口
    锁!代码锁
  • 原文地址:https://www.cnblogs.com/CoderLinkf/p/8922110.html
Copyright © 2011-2022 走看看