2012-04-09 24 views
18

Tôi đang sử dụng mã Entity Framework 4.3.1 trước tiên bằng cách di chuyển rõ ràng. Làm cách nào để thêm mô tả cho các cột trong lớp cấu hình thực thể hoặc di chuyển để nó kết thúc dưới dạng mô tả của một cột trong máy chủ SQL (ví dụ: 2008 R2)?Cách thêm mô tả vào các cột trong Entity Framework 4.3 trước tiên bằng cách sử dụng di chuyển?

Tôi biết tôi có lẽ có thể viết một phương pháp mở rộng cho lớp DbMigration đó sẽ đăng ký sp_updateextendedproperty hoặc sp_addextendedproperty gọi thủ tục như một hoạt động sql di cư bên trong giao dịch chuyển đổi và gọi đó là phần mở rộng sau khi tạo bảng trong cuộc di cư phương pháp Up. Nhưng có một cách xây dựng thanh lịch theo cách mà tôi chưa khám phá? Sẽ là tốt đẹp khi có một thuộc tính mà logic phát hiện thay đổi của di chuyển có thể nhận và tạo ra các cuộc gọi phương thức phê duyệt trong quá trình di chuyển được dàn dựng.

+1

Bạn không cần thêm thuộc tính DataAnnotations? –

Trả lời

10

Tôi cũng cần điều này. Vì vậy, tôi đã dành một ngày và ở đây nó là:

Bộ luật

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

Làm thế nào để sử dụng

Trong file Migrations/Configuration.cs của bạn, thêm này vào cuối của phương pháp Seed:

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

Sau đó, trong bảng điều khiển Trình quản lý gói update-database và nhấn Enter. Vậy đó.

Mã sử ​​dụng thuộc tính lớp [Display(Name="Description here")] trên thuộc tính lớp thực thể của bạn để đặt mô tả.

Vui lòng báo cáo mọi lỗi hoặc đề xuất cải tiến.

Nhờ

Tôi đã sử dụng những mã từ những người khác và tôi muốn nói lời cảm ơn:

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

Tạo một lớp học nhỏ. Vài đề xuất. 1) Wrap với SetColumnDescription() với kiểm tra các thuộc tính ảo. Chỉ thêm các đạo cụ không phải là ảo. 2) Tạo thuộc tính tùy chỉnh thay vì sử dụng Hiển thị. lớp công khai DbTableMetaAttribute: Thuộc tính { _mô tả chuỗi riêng; chuỗi ảo công khai Mô tả { nhận {return _description; } đặt {_description = value; } } } – gnome

+0

Bạn có thể tìm thấy giải pháp sạch hơn cho GetTableName tại http://romiller.com/2014/04/08/ef6-1-mapping-between-types-tables/ –

2

Lưu ý khá hài lòng với câu trả lời hiện tại (nhưng đạo cụ cho công việc!), Tôi muốn một cách để kéo đánh dấu nhận xét hiện có trong các lớp của tôi thay vì sử dụng các thuộc tính. Và theo ý kiến ​​của tôi, tôi không biết tại sao địa ngục mà Microsoft không ủng hộ điều này vì nó có vẻ hiển nhiên nên ở đó!

Đầu tiên, bật tập tin tài liệu XML: Dự án Properties-> dựng-> tài liệu XML File-> App_Data \ YourProjectName.XML

Thứ hai, bao gồm các tập tin như một nguồn tài nguyên nhúng.Xây dựng dự án của bạn, đi tới App_Data, hiển thị các tệp ẩn và bao gồm tệp XML đã được tạo. Chọn tài nguyên được nhúng và Sao chép nếu mới hơn (đây là tùy chọn, bạn có thể chỉ định đường dẫn một cách rõ ràng nhưng theo ý kiến ​​của tôi thì điều này là sạch hơn). Lưu ý, bạn phải sử dụng phương thức này vì đánh dấu không có trong assembly, và sẽ giúp bạn tiết kiệm từ việc định vị nơi lưu trữ XML của bạn.

Đây là việc thực hiện mã mà là một phiên bản sửa đổi của các câu trả lời được chấp nhận:

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

Và lớp mà được đánh dấu bình luận từ visual studio tạo tập tin tài liệu 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

cảm ơn bạn Mr.Mahmoodvcs cho giải pháp tuyệt vời. cho phép tôi để sửa đổi nó chỉ thay thế "DisplayAttribute" với "DescriptionAttribute" insted của việc sử dụng:

[Display(Name="Description here")] 

bạn sẽ sử dụng:

[Description("Description here")] 

nên nó bao gồm bàn là tốt.

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; 
    } 
} 
Các vấn đề liên quan