我想修改生成數據庫模式(DDL)時由EF:CF生成的SQL,如suggested by the Entity Framework team。實體框架6:如何重寫SQL生成器?
這怎麼辦?
我無法通過Google找到任何適合的內容。
我想修改生成數據庫模式(DDL)時由EF:CF生成的SQL,如suggested by the Entity Framework team。實體框架6:如何重寫SQL生成器?
這怎麼辦?
我無法通過Google找到任何適合的內容。
您可以覆蓋所使用的實體框架通過調用你的DbMigrationsConfiguration
類的構造函數的DbMigrationsConfiguration.SetSqlGenerator()方法,將數據庫供應商的名稱(例如"System.Data.SqlClient"
爲SQL Server)的MigrationSqlGenerator
,和MigrationSqlGenerator
實例使用該數據庫供應商。
考慮從the work item你鏈接到例如:
public class MyEntity
{
public int Id { get; set; }
[Required]
[MinLength(5)]
public string Name { get; set; }
}
假設已經生成MyEntity
表和Add-Migration
命令來添加Name
領域。
默認情況下,腳手架遷移:
public partial class AddMyEntity_Name : DbMigration
{
public override void Up()
{
AddColumn("dbo.MyEntity", "Name", c => c.String(nullable: false));
}
public override void Down()
{
DropColumn("dbo.MyEntity", "Name");
}
}
注意,棚架沒有產生的任何MinLengthAttribute
。
要EF傳達最小長度要求,您可以specify an attribute-to-column annotation convention。正如在該文檔頁面中提到的,任何AnnotationValues
都被默認的SQL生成器忽略。
在您的DbContext的OnModelCreating()重寫,添加以下內容:
modelBuilder.Conventions.Add(new AttributeToColumnAnnotationConvention<MinLengthAttribute, Int32>("minLength", (property, attributes) => attributes.Single().Length));
補充說,你可以通過運行Add-Migration -Force AddMyEntity_Name
再生腳手架遷移之後。現在腳手架遷移:
public partial class AddMyEntity_Name : DbMigration
{
public override void Up()
{
AddColumn("dbo.MyEntity", "Name", c => c.String(nullable: false,
annotations: new Dictionary<string, AnnotationValues>
{
{
"minLength",
new AnnotationValues(oldValue: null, newValue: "5")
},
}));
}
public override void Down()
{
DropColumn("dbo.MyEntity", "Name",
removedAnnotations: new Dictionary<string, object>
{
{ "minLength", "5" },
});
}
}
假設,如掛工作項目,要生成一個約束來檢查修整Name
值大於的minLength(5在這種情況下)。
您可以通過創建一個擴展SqlServerMigrationSqlGenerator
定製MigrationSqlGenerator
啓動並調用SetSqlGenerator()來安裝自定義MigrationSqlGenerator
:眼下
internal class CustomSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator
{
protected override void Generate(AddColumnOperation addColumnOperation)
{
base.Generate(addColumnOperation);
}
}
internal sealed class Configuration : DbMigrationsConfiguration<DataContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
SetSqlGenerator("System.Data.SqlClient", new CustomSqlServerMigrationSqlGenerator());
}
protected override void Seed(DataContext context)
{
//...
}
}
,這CustomSqlServerMigrationSqlGenerator
覆蓋生成(AddColumnOperation)方法,而只是調用基地實施。
如果你看看the documentation of AddColumnOperation
,你會看到兩個重要的屬性,Column
和Table
。 Column
是由Up(),c => c.String(nullable: false, annotations: ...)
中的lambda創建的ColumnModel
。
在Generate()方法中,您可以通過ColumnModel
的Annotations
屬性訪問自定義AnnotationValues
。
要生成添加約束的DDL,您需要生成SQL並調用Statement()方法。例如:
internal class CustomSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator
{
protected override void Generate(AddColumnOperation addColumnOperation)
{
base.Generate(addColumnOperation);
var column = addColumnOperation.Column;
if (column.Type == System.Data.Entity.Core.Metadata.Edm.PrimitiveTypeKind.String)
{
var annotations = column.Annotations;
AnnotationValues minLengthValues;
if (annotations.TryGetValue("minLength", out minLengthValues))
{
var minLength = Convert.ToInt32(minLengthValues.NewValue);
if (minLength > 0)
{
if (Convert.ToString(column.DefaultValue).Trim().Length < minLength)
{
throw new ArgumentException(String.Format("minLength {0} specified for {1}.{2}, but the default value, '{3}', does not satisfy this requirement.", minLength, addColumnOperation.Table, column.Name, column.DefaultValue));
}
using (var writer = new StringWriter())
{
writer.Write("ALTER TABLE ");
writer.Write(Name(addColumnOperation.Table));
writer.Write(" ADD CONSTRAINT ");
writer.Write(Quote("ML_" + addColumnOperation.Table + "_" + column.Name));
writer.Write(" CHECK (LEN(LTRIM(RTRIM({0}))) > {1})", Quote(column.Name), minLength);
Statement(writer.ToString());
}
}
}
}
}
}
如果運行Update-Database -Verbose
,你會看到CustomSqlServerMigrationSqlGenerator
生成異常:
minLength 5 specified for dbo.MyEntity.Name, but the default value, '', does not satisfy this requirement.
要解決此問題,請在向上()一個默認值的方法是長於最小長度(如"unknown"
):
public override void Up()
{
AddColumn("dbo.MyEntity", "Name", c => c.String(nullable: false, defaultValue: "unknown",
annotations: new Dictionary<string, AnnotationValues>
{
{
"minLength",
new AnnotationValues(oldValue: null, newValue: "5")
},
}));
}
現在,如果你重新運行Update-Database -Verbose
,你會看到ALTER TABLE
聲明將此列和ALTER TABLE
聲明將約束:
ALTER TABLE [dbo].[MyEntity] ADD [Name] [nvarchar](max) NOT NULL DEFAULT 'unknown' ALTER TABLE [dbo].[MyEntity] ADD CONSTRAINT [ML_dbo.MyEntity_Name] CHECK (LEN(LTRIM(RTRIM([Name]))) > 5)
參見:EF6: Writing Your Own Code First Migration Operations,它展示瞭如何實現自定義的遷移操作。