How to add description to columns in Entity Framework 4.3 code first using migrations?

后端 未结 5 893
一生所求
一生所求 2020-12-01 02:17

I\'m using Entity Framework 4.3.1 code first with explicit migrations. How do I add descriptions for columns either in the entity configuration classes or the migrations, so

5条回答
  •  悲&欢浪女
    2020-12-01 03:02

    While the question is about EF4, this answer targets EF6, which should be appropriate given the passed time since the question was asked.

    I think the Comments belong in the Migration Up and Down methods rather than some Seed method.

    So, as suggested by @MichaelBrown, start with enabling XML Documentation output and include the documentation file as Embedded Resource in your project.

    Then, lets turn the comments into a table/column annotation by using a Convention. There are some tweaks to be made for things like multiline comments and getting rid of excessive whitespace.

    public class CommentConvention : Convention
    {
        public const string NewLinePlaceholder = "<>";
    
        public CommentConvention()
        {
            var docuXml = new XmlDocument();
    
            // Read the documentation xml
            using (var commentStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Namespace.Documentation.xml"))
            {
                docuXml.Load(commentStream);
            }
    
            // configure class/table comment
            Types()
                .Having(pi => docuXml.SelectSingleNode($"//member[starts-with(@name, 'T:{pi?.FullName}')]/summary"))
                .Configure((c, a) =>
                {
                    c.HasTableAnnotation("Comment", GetCommentTextWithNewlineReplacement(a));
                });
    
            // configure property/column comments
            Properties()
                .Having(pi =>
                    docuXml.SelectSingleNode(
                        $"//member[starts-with(@name, 'P:{pi?.DeclaringType?.FullName}.{pi?.Name}')]/summary"))
                .Configure((c, a) => { c.HasColumnAnnotation("Comment", GetCommentTextWithNewlineReplacement(a)); });
        }
    
        // adjust the documentation text to handle newline and whitespace
        private static string GetCommentTextWithNewlineReplacement(XmlNode a)
        {
            if (string.IsNullOrWhiteSpace(a.InnerText))
            {
                return null;
            }
            return string.Join(
                NewLinePlaceholder,
                a.InnerText.Trim()
                    .Split(new string[] {"\r\n", "\r", "\n"}, StringSplitOptions.None)
                    .Select(line => line.Trim()));
        }
    }
    

    Register the convention in the OnModelCreating method.

    Expected Result: When a new Migration is created, the comments will be included as annotations like

    CreateTable(
        "schema.Table",
        c => new
            {
                Id = c.Decimal(nullable: false, precision: 10, scale: 0, identity: true,
                    annotations: new Dictionary
                    {
                        { 
                            "Comment",
                            new AnnotationValues(oldValue: null, newValue: "Commenting the Id Column")
                        },
                    }),
    // ...
    

    Moving on to the second part: adjust the SQL generator to create comments from annotations.

    This one is for Oracle, but MS Sql should be very similar

    class CustomOracleSqlCodeGen : MigrationSqlGenerator
    {
        // the actual SQL generator
        private readonly MigrationSqlGenerator _innerSqlGenerator;
    
        public CustomOracleSqlCodeGen(MigrationSqlGenerator innerSqlGenerator)
        {
            _innerSqlGenerator = innerSqlGenerator;
        }
    
        public override IEnumerable Generate(IEnumerable migrationOperations, string providerManifestToken)
        {
            var ms = _innerSqlGenerator.Generate(AddCommentSqlStatements(migrationOperations), providerManifestToken);
    
            return ms;
        }
    
        // generate additional SQL operations to produce comments
        IEnumerable AddCommentSqlStatements(IEnumerable migrationOperations)
        {
            foreach (var migrationOperation in migrationOperations)
            {
                // the original inputted operation
                yield return migrationOperation;
    
                // create additional operations to produce comments
                if (migrationOperation is CreateTableOperation cto)
                {
                    foreach (var ctoAnnotation in cto.Annotations.Where(x => x.Key == "Comment"))
                    {
                        if (ctoAnnotation.Value is string annotation)
                        {
                            var commentString = annotation.Replace(
                                CommentConvention.NewLinePlaceholder,
                                Environment.NewLine);
    
                            yield return new SqlOperation($"COMMENT ON TABLE {cto.Name} IS '{commentString}'");
                        }
                    }
    
                    foreach (var columnModel in cto.Columns)
                    {
                        foreach (var columnModelAnnotation in columnModel.Annotations.Where(x => x.Key == "Comment"))
                        {
                            if (columnModelAnnotation.Value is AnnotationValues annotation)
                            {
                                var commentString = (annotation.NewValue as string)?.Replace(
                                    CommentConvention.NewLinePlaceholder,
                                    Environment.NewLine);
    
                                yield return new SqlOperation(
                                    $"COMMENT ON COLUMN {cto.Name}.{columnModel.Name} IS '{commentString}'");
                            }
                        }
                    }
                }
            }
        }
    }
    

    In the DbMigrationsConfiguration constructor, register the new code generator (again, this is oracle specific but will be similar for other SQL providers)

    internal sealed class Configuration : DbMigrationsConfiguration
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
            var cg = GetSqlGenerator("Oracle.ManagedDataAccess.Client");
            SetSqlGenerator("Oracle.ManagedDataAccess.Client", new CustomOracleSqlCodeGen(cg));
        }
        // ...
    

    Expected result: The comment annotations from the Up and Down methods are translated to SQL statements that alter the comments in database.

提交回复
热议问题