1、efcore项目中加入类
public class MyMigrationsSqlGenerator : NpgsqlMigrationsSqlGenerator
{
private readonly RelationalTypeMapping _stringTypeMapping;
public MyMigrationsSqlGenerator(MigrationsSqlGeneratorDependencies dependencies, Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal.INpgsqlOptions npgsqlSingletonOptions)
: base(dependencies, npgsqlSingletonOptions)
{
_stringTypeMapping = dependencies.TypeMappingSource.GetMapping(typeof(string))
?? throw new InvalidOperationException("No string type mapping found");
}
protected override void Generate(MigrationOperation operation, IModel? model, MigrationCommandListBuilder builder)
{
base.Generate(operation, model, builder);
if (operation is CreateTableOperation || operation is AlterTableOperation)
CreateTableComment(operation, model, builder);
if (operation is AddColumnOperation || operation is AlterColumnOperation)
CreateColumnComment(operation, model, builder);
}
/// <summary>
/// Create table comment.
/// </summary>
/// <param name="operation"></param>
/// <param name="builder"></param>
private void CreateTableComment(MigrationOperation operation, IModel model, MigrationCommandListBuilder builder)
{
string tableName = string.Empty;
string schema = string.Empty;
string description = string.Empty;
if (operation is AlterTableOperation)
{
var t = operation as AlterColumnOperation;
tableName = (operation as AlterTableOperation).Name;
}
if (operation is CreateTableOperation)
{
var t = operation as CreateTableOperation;
if (t.Name == "__EFMigrationsHistory")
{
return;
}
var addColumnsOperation = t.Columns;
tableName = (operation as CreateTableOperation).Name;
schema = t.Schema;
foreach (var item in addColumnsOperation)
{
CreateColumnComment(item, model, builder);
}
}
description = DbDescriptionHelper.GetDescription(tableName);
if (tableName.IsNullOrWhiteSpace())
throw new Exception("Create table comment error.");
if (!description.IsNullOrEmpty())
{
var sqlHelper = Dependencies.SqlGenerationHelper;
builder
.Append("COMMENT ON TABLE ")
.Append(sqlHelper.DelimitIdentifier(tableName, schema))
.Append(" IS ")
.Append(_stringTypeMapping.GenerateSqlLiteral(description));
builder.AppendLine(";");
}
EndStatement(builder);
}
/// <summary>
/// Create column comment.
/// </summary>
/// <param name="operation"></param>
/// <param name="builder"></param>
private void CreateColumnComment(MigrationOperation operation, IModel model, MigrationCommandListBuilder builder)
{
//alter table a1log modify column UUID VARCHAR(26) comment '修改后的字段注释';
string tableName = string.Empty;
string columnName = string.Empty;
string description = string.Empty;
string schema = string.Empty;
string comment = string.Empty;
if (operation is AlterColumnOperation)
{
var t = (operation as AlterColumnOperation);
tableName = t.Table;
columnName = t.Name;
}
if (operation is AddColumnOperation)
{
var t = (operation as AddColumnOperation);
tableName = t.Table;
columnName = t.Name;
schema = t.Schema;
description = DbDescriptionHelper.GetDescription(tableName, columnName);
}
if (columnName.IsNullOrWhiteSpace() || tableName.IsNullOrWhiteSpace())
throw new Exception("Create columnt comment error." + columnName + "/" + tableName);
if (!description.IsNullOrEmpty())
{
var sqlHelper = Dependencies.SqlGenerationHelper;
builder
.Append("COMMENT ON COLUMN ")
.Append(sqlHelper.DelimitIdentifier(tableName, schema))
.Append(".")
.Append(sqlHelper.DelimitIdentifier(columnName))
.Append(" IS ")
.Append("'")
.Append(description)
.Append("'");
builder.AppendLine(";");
}
EndStatement(builder);
}
}
public class DbDescriptionHelper
{
public static string namespacename = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace;
public static string domainName { get; set; } = "abpvnext.pg.test.Domain";
public static string entityPath { get; set; } = @"E:\code\net\abp\abpvnext.pg.test\src\abpvnext.pg.test.Domain\Entites";
public static List<DbDescription> list { get; set; }
public static string GetDescription(string table, string column = "")
{
if (list == null || list.Count() == 0)
{
list = GetDescription();
}
if (!string.IsNullOrWhiteSpace(table))
{
if (string.IsNullOrWhiteSpace(column))
{
var x = list.FirstOrDefault(p => p.Name == table);
if (x != null)
return x.Description;
return string.Empty;
}
else
{
var x = list.FirstOrDefault(p => p.Name == table);
if (x != null)
{
var y = x.Column;
if (y.Any())
{
var z = y.FirstOrDefault(p => p.Name == column);
if (z != null)
return z.Description;
}
}
return string.Empty;
}
}
else
return string.Empty;
}
public static List<DbDescription> GetDescription()
{
var descriptions = new List<DbDescription>();
var assembly = Assembly.Load(domainName);
var types = assembly?.GetTypes();
var entites = types?
.Where(t => t.IsClass
&& !t.IsGenericType
&& !t.IsAbstract && t.IsAssignableTo<IEntity<Guid>>()
).ToList();
foreach (var entity in entites)
{
var i = new DbDescription();
var entityDir = new System.IO.DirectoryInfo(entityPath);
var allFile = entityDir.GetFiles();
var entityFile = entity.Name + ".cs";
var entityFullPath = allFile.FirstOrDefault(m => m.Name == entityFile)?.FullName;
var entityFileContent = File.ReadAllText(entityFullPath);
entityFileContent = entityFileContent.Substring(entityFileContent.IndexOf("{") + 1, entityFileContent.LastIndexOf("}") - entityFileContent.IndexOf("{") - 1).Replace("\n", "");
var l = entityFileContent.Substring(entityFileContent.IndexOf(" {") + 2, entityFileContent.LastIndexOf(" }") - entityFileContent.IndexOf(" {") - 1).Replace("\n", "");
string[] slipt = { "}\r" };
var m = l.Split(slipt, StringSplitOptions.None).ToList();
var n = new List<DbDescription>();
foreach (var o in m)
{
var p = o.Replace("///", "");
var q = p.IndexOf("<summary>");
var r = p.LastIndexOf("</summary>");
var s = p.IndexOf("public");
var t = p.IndexOf("{");
var u = (q > 0 && r > 0) ? p.Substring(q + 9, r - q - 10).Replace("\r", "").Replace(" ", "") : "";
var v = (s > 0 && t > 0) ? p.Substring(s, t - s).Split(' ')[2] : "";
n.Add(new DbDescription()
{
Description = u,
Name = v
});
}
var w = entityFileContent.Substring(0, entityFileContent.IndexOf("{\r") - 1);
w = w.Replace("///", "");
var x = w.IndexOf("<summary>");
var y = w.LastIndexOf("</summary>");
var z = (x > 0 && y > 0) ? w.Substring(x + 9, y - x - 10).Replace("\r", "").Replace(" ", "") : "";
descriptions.Add(new DbDescription()
{
Name = entity.Name,
Description = z,
Column = n
});
}
return descriptions;
}
}
public class DbDescription
{
public string Name { get; set; }
public string Description { get; set; }
public List<DbDescription> Column { get; set; }
}
domainName:实体所在的命名空间,entityPath:实体代码所在的路径
2、xxxDbContext数据库上下文中相关修改
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.ReplaceService<Microsoft.EntityFrameworkCore.Migrations.IMigrationsSqlGenerator, MyMigrationsSqlGenerator>();
base.OnConfiguring(optionsBuilder);
}
3、xxxDbContextFactory 类中CreateDbContext方法
public testDbContext CreateDbContext(string[] args)
{
// https://www.npgsql.org/efcore/release-notes/6.0.html#opting-out-of-the-new-timestamp-mapping-logic
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
testEfCoreEntityExtensionMappings.Configure();
var configuration = BuildConfiguration();
var builder = new DbContextOptionsBuilder<testDbContext>()
.UseNpgsql(configuration.GetConnectionString("Default")).ReplaceService<Microsoft.EntityFrameworkCore.Migrations.IMigrationsSqlGenerator, MyMigrationsSqlGenerator>();
return new testDbContext(builder.Options);
}