2012-04-09 5 views
18

Ich verwende Entity Framework 4.3.1 Code zuerst mit expliziten Migrationen. Wie füge ich Beschreibungen für Spalten entweder in den Entitätskonfigurationsklassen oder den Migrationen hinzu, sodass sie als Beschreibung einer Spalte im SQL Server (z. B. 2008 R2) enden?Wie können Sie Spalten in Entity Framework 4.3 Code zuerst mithilfe von Migrationen hinzufügen?

Ich weiß, dass ich wahrscheinlich eine Erweiterungsmethode für die DbMigration Klasse schreiben, die den sp_updateextendedproperty oder sp_addextendedproperty Prozeduraufruf als SQL-Operation zur Migration innerhalb der Migration Transaktion registrieren würden und dass die Verlängerung nach der Tabellenerstellung in der Up Methode Migration nennen. Aber gibt es einen eleganten Weg, den ich noch entdecken muss? Es wäre schön, ein Attribut zu haben, das die Änderungsdetektionslogik der Migrationen in der gerüsteten Migration appropritieren Methodenaufrufe erfassen und generieren kann.

+1

Sie müssen kein DataAnnotations-Attribut hinzufügen? –

Antwort

10

Ich brauchte das auch. So verbrachte ich einen Tag und hier ist es:

Der Kodex

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; 
     } 
    } 

So verwenden

In Ihrer Migrations/Configuration.cs Datei, fügen Sie diese am Ende der Seed Methode:

DbDescriptionUpdater<ContextClass> updater = new DbDescriptionUpdater<ContextClass>(context); 
updater.UpdateDatabaseDescriptions(); 

Geben Sie dann in der Package Manager-Konsole 012 einund drücken Sie die Eingabetaste. Das ist es.

Der Code verwendet das Attribut [Display(Name="Description here")] für die Eigenschaften Ihrer Entitätsklasse, um die Beschreibung festzulegen.

Bitte melden Sie jeden Fehler oder schlagen Sie Verbesserungen vor.

Dank

Ich habe diesen Code von anderen Leuten, und ich mag sagen, dank verwendet:

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

+1

Erstellen Sie kleine Klasse. Ein paar Empfehlungen. 1) Umbrechen Sie mit SetColumnDescription() mit der Prüfung auf virtuelle Eigenschaften. Fügen Sie nur Requisiten hinzu, die nicht virtuell sind. 2) Erstellen Sie ein benutzerdefiniertes Attribut, anstatt Display zu verwenden. Öffentliche Klasse DbTableMetaAttribute: Attribut { private Zeichenfolge _description; öffentliche virtuelle Zeichenfolge Beschreibung { get {return _description; } set {_description = Wert; } } } – gnome

+0

Sie finden eine sauberere Lösung für GetTableName bei http://romiller.com/2014/04/08/ef6-1-mapping-between-types-tables/ –

2

Hinweis ziemlich zufrieden mit der aktuellen Antwort (aber Requisiten für die Arbeit!), Ich wollte eine Möglichkeit, das vorhandene Kommentar Markup in meinen Klassen statt Attribute zu ziehen. Und meiner Meinung nach weiß ich nicht, warum zur Hölle Microsoft das nicht unterstützt hat, da es offensichtlich scheint, dass es da sein sollte!

Aktivieren Sie zunächst XML-Dokumentationsdatei: Projekt Eigenschaften-> Build-> XML-Dokumentation File-> App_Data \ YourProjectName.XML

Zweitens enthält die Datei als eingebettete Ressource.Erstellen Sie Ihr Projekt, gehen Sie zu App_Data, zeigen Sie versteckte Dateien an und fügen Sie die generierte XML-Datei ein. Wählen Sie die eingebettete Ressource und Kopieren, falls neuere (das ist optional, Sie könnten den Pfad explizit angeben, aber meiner Meinung nach ist dies sauberer). Beachten Sie, dass Sie diese Methode verwenden müssen, da das Markup in der Assembly nicht vorhanden ist und Sie nicht mehr nach dem Speicherort Ihrer XML-Datei suchen. Hier

ist die Code-Implementierung, die eine modifizierte Version der akzeptierte Antwort ist:

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; 
    } 
} 

Und die Klasse, die den Kommentar Markup aus dem Visual Studio wird XML-Dokumentationsdatei erzeugt:

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

danke Mr.Mahmoodvcs für die großartige Lösung. erlauben Sie mir, es einfach zu ändern ersetzen "DisplayAttribute" mit "Description" insted mit:

[Display(Name="Description here")] 

Sie verwenden:

[Description("Description here")] 

so enthält es die Tabelle auch.

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; 
    } 
} 
Verwandte Themen