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
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.