回答

15

您可以覆蓋所使用的實體框架通過調用你的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,你會看到兩個重要的屬性,ColumnTableColumn是由Up(),c => c.String(nullable: false, annotations: ...)中的lambda創建的ColumnModel

在Generate()方法中,您可以通過ColumnModelAnnotations屬性訪問自定義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,它展示瞭如何實現自定義的遷移操作。