2012-04-09 4 views
18

私はEntity Framework 4.3.1のコードを先に明示的に移行しています。エンティティ構成クラスまたは移行の列の説明を追加して、SQL Serverの列の説明(例:2008 R2)になるようにするにはどうすればよいですか。最初に移行を使用してEntity Framework 4.3のコードの列に説明を追加する方法はありますか?

私はおそらく移行トランザクション内のSQLマイグレーション操作としてsp_updateextendedpropertyまたはsp_addextendedpropertyプロシージャ・コールを登録し、移行Up方法でテーブルを作成した後、その拡張子を呼ぶだろうDbMigrationクラスの拡張メソッドを書くことができます知っています。しかし、私がまだ発見していないようにエレガントに造られていますか?マイグレーションの変更検出ロジックが拾うことができ、スキャフォールドされた移行で適切なメソッド呼び出しを生成できるという属性を持つことは良いことでしょう。

+1

DataAnnotations属性を追加する必要はありませんか? –

答えて

10

私もこれを必要としていました。だから私は一日を過ごしたとここにある:

コード、あなたのMigrations/Configuration.csファイルで

を使用Seedメソッドの最後にこれを追加する方法

public class DbDescriptionUpdater<TContext> 
     where TContext : System.Data.Entity.DbContext 
    { 
     public DbDescriptionUpdater(TContext context) 
     { 
      this.context = context; 
     } 

     Type contextType; 
     TContext context; 
     DbTransaction transaction; 
     public void UpdateDatabaseDescriptions() 
     { 
      contextType = typeof(TContext); 
      this.context = context; 
      var props = contextType.GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); 
      transaction = null; 
      try 
      { 
       context.Database.Connection.Open(); 
       transaction = context.Database.Connection.BeginTransaction(); 
       foreach (var prop in props) 
       { 
        if (prop.PropertyType.InheritsOrImplements((typeof(DbSet<>)))) 
        { 
         var tableType = prop.PropertyType.GetGenericArguments()[0]; 
         SetTableDescriptions(tableType); 
        } 
       } 
       transaction.Commit(); 
      } 
      catch 
      { 
       if (transaction != null) 
        transaction.Rollback(); 
       throw; 
      } 
      finally 
      { 
       if (context.Database.Connection.State == System.Data.ConnectionState.Open) 
        context.Database.Connection.Close(); 
      } 
     } 

     private void SetTableDescriptions(Type tableType) 
     { 
      string fullTableName = context.GetTableName(tableType); 
      Regex regex = new Regex(@"(\[\w+\]\.)?\[(?<table>.*)\]"); 
      Match match = regex.Match(fullTableName); 
      string tableName; 
      if (match.Success) 
       tableName = match.Groups["table"].Value; 
      else 
       tableName = fullTableName; 

      var tableAttrs = tableType.GetCustomAttributes(typeof(TableAttribute), false); 
      if (tableAttrs.Length > 0) 
       tableName = ((TableAttribute)tableAttrs[0]).Name; 
      foreach (var prop in tableType.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)) 
      { 
       if (prop.PropertyType.IsClass && prop.PropertyType != typeof(string)) 
        continue; 
       var attrs = prop.GetCustomAttributes(typeof(DisplayAttribute), false); 
       if (attrs.Length > 0) 
        SetColumnDescription(tableName, prop.Name, ((DisplayAttribute)attrs[0]).Name); 
      } 
     } 

     private void SetColumnDescription(string tableName, string columnName, string description) 
     { 
      string strGetDesc = "select [value] from fn_listextendedproperty('MS_Description','schema','dbo','table',N'" + tableName + "','column',null) where objname = N'" + columnName + "';"; 
      var prevDesc = RunSqlScalar(strGetDesc); 
      if (prevDesc == null) 
      { 
       RunSql(@"EXEC sp_addextendedproperty 
@name = N'MS_Description', @value = @desc, 
@level0type = N'Schema', @level0name = 'dbo', 
@level1type = N'Table', @level1name = @table, 
@level2type = N'Column', @level2name = @column;", 
                 new SqlParameter("@table", tableName), 
                 new SqlParameter("@column", columnName), 
                 new SqlParameter("@desc", description)); 
      } 
      else 
      { 
       RunSql(@"EXEC sp_updateextendedproperty 
@name = N'MS_Description', @value = @desc, 
@level0type = N'Schema', @level0name = 'dbo', 
@level1type = N'Table', @level1name = @table, 
@level2type = N'Column', @level2name = @column;", 
                 new SqlParameter("@table", tableName), 
                 new SqlParameter("@column", columnName), 
                 new SqlParameter("@desc", description)); 
      } 
     } 

     DbCommand CreateCommand(string cmdText, params SqlParameter[] parameters) 
     { 
      var cmd = context.Database.Connection.CreateCommand(); 
      cmd.CommandText = cmdText; 
      cmd.Transaction = transaction; 
      foreach (var p in parameters) 
       cmd.Parameters.Add(p); 
      return cmd; 
     } 
     void RunSql(string cmdText, params SqlParameter[] parameters) 
     { 
      var cmd = CreateCommand(cmdText, parameters); 
      cmd.ExecuteNonQuery(); 
     } 
     object RunSqlScalar(string cmdText, params SqlParameter[] parameters) 
     { 
      var cmd = CreateCommand(cmdText, parameters); 
      return cmd.ExecuteScalar(); 
     } 

    } 
    public static class ReflectionUtil 
    { 

     public static bool InheritsOrImplements(this Type child, Type parent) 
     { 
      parent = ResolveGenericTypeDefinition(parent); 

      var currentChild = child.IsGenericType 
            ? child.GetGenericTypeDefinition() 
            : child; 

      while (currentChild != typeof(object)) 
      { 
       if (parent == currentChild || HasAnyInterfaces(parent, currentChild)) 
        return true; 

       currentChild = currentChild.BaseType != null 
           && currentChild.BaseType.IsGenericType 
            ? currentChild.BaseType.GetGenericTypeDefinition() 
            : currentChild.BaseType; 

       if (currentChild == null) 
        return false; 
      } 
      return false; 
     } 

     private static bool HasAnyInterfaces(Type parent, Type child) 
     { 
      return child.GetInterfaces() 
       .Any(childInterface => 
       { 
        var currentInterface = childInterface.IsGenericType 
         ? childInterface.GetGenericTypeDefinition() 
         : childInterface; 

        return currentInterface == parent; 
       }); 
     } 

     private static Type ResolveGenericTypeDefinition(Type parent) 
     { 
      var shouldUseGenericType = true; 
      if (parent.IsGenericType && parent.GetGenericTypeDefinition() != parent) 
       shouldUseGenericType = false; 

      if (parent.IsGenericType && shouldUseGenericType) 
       parent = parent.GetGenericTypeDefinition(); 
      return parent; 
     } 
    } 

    public static class ContextExtensions 
    { 
     public static string GetTableName(this DbContext context, Type tableType) 
     { 
      MethodInfo method = typeof(ContextExtensions).GetMethod("GetTableName", new Type[] { typeof(DbContext) }) 
          .MakeGenericMethod(new Type[] { tableType }); 
      return (string)method.Invoke(context, new object[] { context }); 
     } 
     public static string GetTableName<T>(this DbContext context) where T : class 
     { 
      ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext; 

      return objectContext.GetTableName<T>(); 
     } 

     public static string GetTableName<T>(this ObjectContext context) where T : class 
     { 
      string sql = context.CreateObjectSet<T>().ToTraceString(); 
      Regex regex = new Regex("FROM (?<table>.*) AS"); 
      Match match = regex.Match(sql); 

      string table = match.Groups["table"].Value; 
      return table; 
     } 
    } 

パッケージマネージャコンソールタイプ012で次に
DbDescriptionUpdater<ContextClass> updater = new DbDescriptionUpdater<ContextClass>(context); 
updater.UpdateDatabaseDescriptions(); 
と入力してEnterキーを押します。 それだけです。

コードは、説明を設定するには、エンティティ・クラスのプロパティに[Display(Name="Description here")]属性を使用しています。

どんなバグを報告したり、改善点を提案してください。

adding a column description

Check if a class is derived from a generic class

Get Database Table Name from Entity Framework MetaData

Generics in C#, using type of a variable as parameter:私は他の人からのこれらのコードを使用しましたし、私は感謝を言いたい

感謝210

+1

小さなクラスを作成します。いくつかの推奨事項。 1)SetColumnDescription()で仮想プロパティのチェックをラップします。仮想ではない小道具だけを追加してください。 2)表示を使用せずにカスタム属性を作成します。パブリッククラスDbTableMetaAttribute:属性 { プライベート文字列_description; パブリック仮想文字列説明 { get {return _description; } セット{_description = value; } } } – gnome

+0

GetTableNameのクリーンなソリューションは、http://romiller.com/2014/04/08/ef6-1-mapping-between-types-tables/にあります。 –

2

現在の答えに満足ノート(ただし、仕事のための小道具は!)、私の代わりに属性を使用しての私のクラスで既存のコメントマークアップをプルする方法を求めていました。そして私の意見では、マイクロソフトがなぜこれをサポートしていないのか分かりませんが、明らかにそこにあるはずです。

まず、XMLドキュメントファイルをオンにする:プロジェクトプロパティ - >ビルド - > XMLドキュメントファイル - > App_Dataに\ YourProjectName.XML

第二には、埋め込みリソースとしてファイルが含まれています。プロジェクトをビルドし、App_Dataに行き、隠しファイルを表示し、生成されたXMLファイルを含めます。埋め込みリソースを選択し、より新しい場合はコピーしてください(これはオプションですが、パスを明示的に指定できますが、私の意見ではよりクリーンです)。アセンブリにマークアップが存在しないため、このメソッドを使用する必要があります。これにより、XMLが格納されている場所を特定できなくなります。

public class SchemaDescriptionUpdater<TContext> where TContext : DbContext 
{ 
    Type contextType; 
    TContext context; 
    DbTransaction transaction; 
    XmlAnnotationReader reader; 
    public SchemaDescriptionUpdater(TContext context) 
    { 
     this.context = context; 
     reader = new XmlAnnotationReader(); 
    } 
    public SchemaDescriptionUpdater(TContext context, string xmlDocumentationPath) 
    { 
     this.context = context; 
     reader = new XmlAnnotationReader(xmlDocumentationPath); 
    } 

    public void UpdateDatabaseDescriptions() 
    { 
     contextType = typeof(TContext); 
     var props = contextType.GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); 
     transaction = null; 
     try 
     { 
      context.Database.Connection.Open(); 
      transaction = context.Database.Connection.BeginTransaction(); 
      foreach (var prop in props) 
      { 
       if (prop.PropertyType.InheritsOrImplements((typeof(DbSet<>)))) 
       { 
        var tableType = prop.PropertyType.GetGenericArguments()[0]; 
        SetTableDescriptions(tableType); 
       } 
      } 
      transaction.Commit(); 
     } 
     catch 
     { 
      if (transaction != null) 
       transaction.Rollback(); 
      throw; 
     } 
     finally 
     { 
      if (context.Database.Connection.State == System.Data.ConnectionState.Open) 
       context.Database.Connection.Close(); 
     } 
    } 

    private void SetTableDescriptions(Type tableType) 
    { 
     string fullTableName = context.GetTableName(tableType); 
     Regex regex = new Regex(@"(\[\w+\]\.)?\[(?<table>.*)\]"); 
     Match match = regex.Match(fullTableName); 
     string tableName; 
     if (match.Success) 
      tableName = match.Groups["table"].Value; 
     else 
      tableName = fullTableName; 

     var tableAttrs = tableType.GetCustomAttributes(typeof(TableAttribute), false); 
     if (tableAttrs.Length > 0) 
      tableName = ((TableAttribute)tableAttrs[0]).Name; 

     // set the description for the table 
     string tableComment = reader.GetCommentsForResource(tableType, null, XmlResourceType.Type); 
     if (!string.IsNullOrEmpty(tableComment)) 
      SetDescriptionForObject(tableName, null, tableComment); 

     // get all of the documentation for each property/column 
     ObjectDocumentation[] columnComments = reader.GetCommentsForResource(tableType); 
     foreach (var column in columnComments) 
     { 
      SetDescriptionForObject(tableName, column.PropertyName, column.Documentation); 
     } 
    } 

    private void SetDescriptionForObject(string tableName, string columnName, string description) 
    { 
     string strGetDesc = ""; 
     // determine if there is already an extended description 
     if(string.IsNullOrEmpty(columnName)) 
      strGetDesc = "select [value] from fn_listextendedproperty('MS_Description','schema','dbo','table',N'" + tableName + "',null,null);"; 
     else 
      strGetDesc = "select [value] from fn_listextendedproperty('MS_Description','schema','dbo','table',N'" + tableName + "','column',null) where objname = N'" + columnName + "';"; 
     var prevDesc = (string)RunSqlScalar(strGetDesc); 

     var parameters = new List<SqlParameter> 
     { 
      new SqlParameter("@table", tableName), 
      new SqlParameter("@desc", description) 
     }; 

     // is it an update, or new? 
     string funcName = "sp_addextendedproperty"; 
     if (!string.IsNullOrEmpty(prevDesc)) 
      funcName = "sp_updateextendedproperty"; 

     string query = @"EXEC " + funcName + @" @name = N'MS_Description', @value = @desc,@level0type = N'Schema', @level0name = 'dbo',@level1type = N'Table', @level1name = @table"; 

     // if a column is specified, add a column description 
     if (!string.IsNullOrEmpty(columnName)) 
     { 
      parameters.Add(new SqlParameter("@column", columnName)); 
      query += ", @level2type = N'Column', @level2name = @column"; 
     } 
     RunSql(query, parameters.ToArray()); 
    } 

    DbCommand CreateCommand(string cmdText, params SqlParameter[] parameters) 
    { 
     var cmd = context.Database.Connection.CreateCommand(); 
     cmd.CommandText = cmdText; 
     cmd.Transaction = transaction; 
     foreach (var p in parameters) 
      cmd.Parameters.Add(p); 
     return cmd; 
    } 
    void RunSql(string cmdText, params SqlParameter[] parameters) 
    { 
     var cmd = CreateCommand(cmdText, parameters); 
     cmd.ExecuteNonQuery(); 
    } 
    object RunSqlScalar(string cmdText, params SqlParameter[] parameters) 
    { 
     var cmd = CreateCommand(cmdText, parameters); 
     return cmd.ExecuteScalar(); 
    } 

} 

public static class ReflectionUtil 
{ 
    public static bool InheritsOrImplements(this Type child, Type parent) 
    { 
     parent = ResolveGenericTypeDefinition(parent); 

     var currentChild = child.IsGenericType 
           ? child.GetGenericTypeDefinition() 
           : child; 

     while (currentChild != typeof(object)) 
     { 
      if (parent == currentChild || HasAnyInterfaces(parent, currentChild)) 
       return true; 

      currentChild = currentChild.BaseType != null 
          && currentChild.BaseType.IsGenericType 
           ? currentChild.BaseType.GetGenericTypeDefinition() 
           : currentChild.BaseType; 

      if (currentChild == null) 
       return false; 
     } 
     return false; 
    } 

    private static bool HasAnyInterfaces(Type parent, Type child) 
    { 
     return child.GetInterfaces() 
      .Any(childInterface => 
      { 
       var currentInterface = childInterface.IsGenericType 
        ? childInterface.GetGenericTypeDefinition() 
        : childInterface; 

       return currentInterface == parent; 
      }); 
    } 

    private static Type ResolveGenericTypeDefinition(Type parent) 
    { 
     var shouldUseGenericType = true; 
     if (parent.IsGenericType && parent.GetGenericTypeDefinition() != parent) 
      shouldUseGenericType = false; 

     if (parent.IsGenericType && shouldUseGenericType) 
      parent = parent.GetGenericTypeDefinition(); 
     return parent; 
    } 
} 

public static class ContextExtensions 
{ 
    public static string GetTableName(this DbContext context, Type tableType) 
    { 
     MethodInfo method = typeof(ContextExtensions).GetMethod("GetTableName", new Type[] { typeof(DbContext) }) 
         .MakeGenericMethod(new Type[] { tableType }); 
     return (string)method.Invoke(context, new object[] { context }); 
    } 
    public static string GetTableName<T>(this DbContext context) where T : class 
    { 
     ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext; 

     return objectContext.GetTableName<T>(); 
    } 

    public static string GetTableName<T>(this ObjectContext context) where T : class 
    { 
     string sql = context.CreateObjectSet<T>().ToTraceString(); 
     Regex regex = new Regex("FROM (?<table>.*) AS"); 
     Match match = regex.Match(sql); 

     string table = match.Groups["table"].Value; 
     return table; 
    } 
} 

とVisual Studioからコメントマークアップを取得するクラスは、XMLドキュメントファイル生成:

public class XmlAnnotationReader 
{ 
    public string XmlPath { get; protected internal set; } 
    public XmlDocument Document { get; protected internal set; } 

    public XmlAnnotationReader() 
    { 
     var assembly = Assembly.GetExecutingAssembly(); 
     string resourceName = String.Format("{0}.App_Data.{0}.XML", assembly.GetName().Name); 
     this.XmlPath = resourceName; 
     using (Stream stream = assembly.GetManifestResourceStream(resourceName)) 
     { 
      using (StreamReader reader = new StreamReader(stream)) 
      { 
       XmlDocument doc = new XmlDocument(); 
       //string result = reader.ReadToEnd(); 
       doc.Load(reader); 
       this.Document = doc; 
      } 
     } 
    } 

    public XmlAnnotationReader(string xmlPath) 
    { 
     this.XmlPath = xmlPath; 
     if (File.Exists(xmlPath)) 
     { 
      XmlDocument doc = new XmlDocument(); 
      doc.Load(this.XmlPath); 
      this.Document = doc; 
     } 
     else 
      throw new FileNotFoundException(String.Format("Could not find the XmlDocument at the specified path: {0}\r\nCurrent Path: {1}", xmlPath, Assembly.GetExecutingAssembly().Location)); 
    } 

    /// <summary> 
    /// Retrievethe XML comments documentation for a given resource 
    /// Eg. ITN.Data.Models.Entity.TestObject.MethodName 
    /// </summary> 
    /// <returns></returns> 
    public string GetCommentsForResource(string resourcePath, XmlResourceType type) 
    { 

     XmlNode node = Document.SelectSingleNode(String.Format("//member[starts-with(@name, '{0}:{1}')]/summary", GetObjectTypeChar(type), resourcePath)); 
     if (node != null) 
     { 
      string xmlResult = node.InnerText; 
      string trimmedResult = Regex.Replace(xmlResult, @"\s+", " "); 
      return trimmedResult; 
     } 
     return string.Empty; 
    } 

    /// <summary> 
    /// Retrievethe XML comments documentation for a given resource 
    /// Eg. ITN.Data.Models.Entity.TestObject.MethodName 
    /// </summary> 
    /// <returns></returns> 
    public ObjectDocumentation[] GetCommentsForResource(Type objectType) 
    { 
     List<ObjectDocumentation> comments = new List<ObjectDocumentation>(); 
     string resourcePath = objectType.FullName; 

     PropertyInfo[] properties = objectType.GetProperties(); 
     FieldInfo[] fields = objectType.GetFields(); 
     List<ObjectDocumentation> objectNames = new List<ObjectDocumentation>(); 
     objectNames.AddRange(properties.Select(x => new ObjectDocumentation() { PropertyName = x.Name, Type = XmlResourceType.Property }).ToList()); 
     objectNames.AddRange(properties.Select(x => new ObjectDocumentation() { PropertyName = x.Name, Type = XmlResourceType.Field }).ToList()); 

     foreach (var property in objectNames) 
     { 
      XmlNode node = Document.SelectSingleNode(String.Format("//member[starts-with(@name, '{0}:{1}.{2}')]/summary", GetObjectTypeChar(property.Type), resourcePath, property.PropertyName)); 
      if (node != null) 
      { 
       string xmlResult = node.InnerText; 
       string trimmedResult = Regex.Replace(xmlResult, @"\s+", " "); 
       property.Documentation = trimmedResult; 
       comments.Add(property); 
      } 
     } 
     return comments.ToArray(); 
    } 

    /// <summary> 
    /// Retrievethe XML comments documentation for a given resource 
    /// </summary> 
    /// <param name="objectType">The type of class to retrieve documenation on</param> 
    /// <param name="propertyName">The name of the property in the specified class</param> 
    /// <param name="resourceType"></param> 
    /// <returns></returns> 
    public string GetCommentsForResource(Type objectType, string propertyName, XmlResourceType resourceType) 
    { 
     List<ObjectDocumentation> comments = new List<ObjectDocumentation>(); 
     string resourcePath = objectType.FullName; 

     string scopedElement = resourcePath; 
     if (propertyName != null && resourceType != XmlResourceType.Type) 
      scopedElement += "." + propertyName; 
     XmlNode node = Document.SelectSingleNode(String.Format("//member[starts-with(@name, '{0}:{1}')]/summary", GetObjectTypeChar(resourceType), scopedElement)); 
     if (node != null) 
     { 
      string xmlResult = node.InnerText; 
      string trimmedResult = Regex.Replace(xmlResult, @"\s+", " "); 
      return trimmedResult; 
     } 
     return string.Empty; 
    } 

    private string GetObjectTypeChar(XmlResourceType type) 
    { 
     switch (type) 
     { 
      case XmlResourceType.Field: 
       return "F"; 
      case XmlResourceType.Method: 
       return "M"; 
      case XmlResourceType.Property: 
       return "P"; 
      case XmlResourceType.Type: 
       return "T"; 

     } 
     return string.Empty; 
    } 
} 

public class ObjectDocumentation 
{ 
    public string PropertyName { get; set; } 
    public string Documentation { get; set; } 
    public XmlResourceType Type { get; set; } 
} 

public enum XmlResourceType 
{ 
    Method, 
    Property, 
    Field, 
    Type 
} 
0

をここで

は受け入れ答えの修正版でコードの実装です素晴らしいソリューションのためにMr.Mahmoodvcsありがとうございます。 は私がちょうど "DescriptionAttribute" で "DisplayAttribute" を置き換え、それを修正することができます使用するのではinsted:

あなたが使用する
[Display(Name="Description here")] 

[Description("Description here")] 

をので、それは同様にテーブルを含んでいます。

public class DbDescriptionUpdater<TContext> 
    where TContext : System.Data.Entity.DbContext 
{ 
    public DbDescriptionUpdater(TContext context) 
    { 
     this.context = context; 
    } 

    Type contextType; 
    TContext context; 
    DbTransaction transaction; 
    public void UpdateDatabaseDescriptions() 
    { 
     contextType = typeof(TContext); 
     this.context = context; 
     var props = contextType.GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public); 
     transaction = null; 
     try 
     { 
      context.Database.Connection.Open(); 
      transaction = context.Database.Connection.BeginTransaction(); 
      foreach (var prop in props) 
      { 
       if (prop.PropertyType.InheritsOrImplements((typeof(DbSet<>)))) 
       { 
        var tableType = prop.PropertyType.GetGenericArguments()[0]; 
        SetTableDescriptions(tableType); 
       } 
      } 
      transaction.Commit(); 
     } 
     catch 
     { 
      if (transaction != null) 
       transaction.Rollback(); 
      throw; 
     } 
     finally 
     { 
      if (context.Database.Connection.State == System.Data.ConnectionState.Open) 
       context.Database.Connection.Close(); 
     } 
    } 

    private void SetTableDescriptions(Type tableType) 
    { 
     string fullTableName = context.GetTableName(tableType); 
     Regex regex = new Regex(@"(\[\w+\]\.)?\[(?<table>.*)\]"); 
     Match match = regex.Match(fullTableName); 
     string tableName; 
     if (match.Success) 
      tableName = match.Groups["table"].Value; 
     else 
      tableName = fullTableName; 

     var tableAttrs = tableType.GetCustomAttributes(typeof(TableAttribute), false); 
     if (tableAttrs.Length > 0) 
      tableName = ((TableAttribute)tableAttrs[0]).Name; 
     var table_attrs = tableType.GetCustomAttributes(typeof(DescriptionAttribute), false); 
     if (table_attrs != null && table_attrs.Length > 0) 
      SetTableDescription(tableName, ((DescriptionAttribute)table_attrs[0]).Description); 
     foreach (var prop in tableType.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)) 
     { 
      if (prop.PropertyType.IsClass && prop.PropertyType != typeof(string)) 
       continue; 
      var attrs = prop.GetCustomAttributes(typeof(DescriptionAttribute), false); 
      if (attrs != null && attrs.Length > 0) 
       SetColumnDescription(tableName, prop.Name, ((DescriptionAttribute)attrs[0]).Description); 
     } 
    } 

    private void SetColumnDescription(string tableName, string columnName, string description) 
    { 

     string strGetDesc = "select [value] from fn_listextendedproperty('MS_Description','schema','dbo','table',N'" + tableName + "','column',null) where objname = N'" + columnName + "';"; 
     var prevDesc = RunSqlScalar(strGetDesc); 
     if (prevDesc == null) 
     { 
      RunSql(@"EXEC sp_addextendedproperty 
       @name = N'MS_Description', @value = @desc, 
       @level0type = N'Schema', @level0name = 'dbo', 
       @level1type = N'Table', @level1name = @table, 
       @level2type = N'Column', @level2name = @column;", 
                new SqlParameter("@table", tableName), 
                new SqlParameter("@column", columnName), 
                new SqlParameter("@desc", description)); 
     } 
     else 
     { 
      RunSql(@"EXEC sp_updateextendedproperty 
        @name = N'MS_Description', @value = @desc, 
        @level0type = N'Schema', @level0name = 'dbo', 
        @level1type = N'Table', @level1name = @table, 
        @level2type = N'Column', @level2name = @column;", 
                new SqlParameter("@table", tableName), 
                new SqlParameter("@column", columnName), 
                new SqlParameter("@desc", description)); 
     } 
    } 
    private void SetTableDescription(string tableName, string description) 
    { 

     string strGetDesc = "select [value] from fn_listextendedproperty('MS_Description','schema','dbo','table',N'" + tableName + "',null,null);"; 
     var prevDesc = RunSqlScalar(strGetDesc); 
     if (prevDesc == null) 
     { 
      RunSql(@"EXEC sp_addextendedproperty 
        @name = N'MS_Description', @value = @desc, 
        @level0type = N'Schema', @level0name = 'dbo', 
        @level1type = N'Table', @level1name = @table;", 
                new SqlParameter("@table", tableName), 
                new SqlParameter("@desc", description)); 
     } 
     else 
     { 
      RunSql(@"EXEC sp_updateextendedproperty 
        @name = N'MS_Description', @value = @desc, 
        @level0type = N'Schema', @level0name = 'dbo', 
        @level1type = N'Table', @level1name = @table;", 
                new SqlParameter("@table", tableName), 
                new SqlParameter("@desc", description)); 
     } 
    } 
    DbCommand CreateCommand(string cmdText, params SqlParameter[] parameters) 
    { 
     var cmd = context.Database.Connection.CreateCommand(); 
     cmd.CommandText = cmdText; 
     cmd.Transaction = transaction; 
     foreach (var p in parameters) 
      cmd.Parameters.Add(p); 
     return cmd; 
    } 
    void RunSql(string cmdText, params SqlParameter[] parameters) 
    { 
     var cmd = CreateCommand(cmdText, parameters); 
     cmd.ExecuteNonQuery(); 
    } 
    object RunSqlScalar(string cmdText, params SqlParameter[] parameters) 
    { 
     var cmd = CreateCommand(cmdText, parameters); 
     return cmd.ExecuteScalar(); 
    } 

} 
public static class ReflectionUtil 
{ 

    public static bool InheritsOrImplements(this Type child, Type parent) 
    { 
     parent = ResolveGenericTypeDefinition(parent); 

     var currentChild = child.IsGenericType 
           ? child.GetGenericTypeDefinition() 
           : child; 

     while (currentChild != typeof(object)) 
     { 
      if (parent == currentChild || HasAnyInterfaces(parent, currentChild)) 
       return true; 

      currentChild = currentChild.BaseType != null 
          && currentChild.BaseType.IsGenericType 
           ? currentChild.BaseType.GetGenericTypeDefinition() 
           : currentChild.BaseType; 

      if (currentChild == null) 
       return false; 
     } 
     return false; 
    } 

    private static bool HasAnyInterfaces(Type parent, Type child) 
    { 
     return child.GetInterfaces() 
      .Any(childInterface => 
      { 
       var currentInterface = childInterface.IsGenericType 
        ? childInterface.GetGenericTypeDefinition() 
        : childInterface; 

       return currentInterface == parent; 
      }); 
    } 

    private static Type ResolveGenericTypeDefinition(Type parent) 
    { 
     var shouldUseGenericType = true; 
     if (parent.IsGenericType && parent.GetGenericTypeDefinition() != parent) 
      shouldUseGenericType = false; 

     if (parent.IsGenericType && shouldUseGenericType) 
      parent = parent.GetGenericTypeDefinition(); 
     return parent; 
    } 
} 

public static class ContextExtensions 
{ 
    public static string GetTableName(this DbContext context, Type tableType) 
    { 
     MethodInfo method = typeof(ContextExtensions).GetMethod("GetTableName", new Type[] { typeof(DbContext) }) 
         .MakeGenericMethod(new Type[] { tableType }); 
     return (string)method.Invoke(context, new object[] { context }); 
    } 
    public static string GetTableName<T>(this DbContext context) where T : class 
    { 
     ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext; 

     return objectContext.GetTableName<T>(); 
    } 

    public static string GetTableName<T>(this ObjectContext context) where T : class 
    { 
     string sql = context.CreateObjectSet<T>().ToTraceString(); 
     Regex regex = new Regex("FROM (?<table>.*) AS"); 
     Match match = regex.Match(sql); 

     string table = match.Groups["table"].Value; 
     return table; 
    } 
} 
関連する問題