如何在Entity Framework中为JSON添加检查约束?

时间:2016-09-26 12:29:13

标签: json entity-framework code-first sql-server-2016

使用

为表格字段添加JSON CHECK CONSTRAINT
ALTER TABLE [dbo].[Data]  
   ADD CONSTRAINT [JsonData must be formatted as JSON] 
   CHECK  (IsJson([JsonData]) > 0)

工作正常,但我想让它适用于Code First。

我尝试了Reverse Engineering Code First,但它对我没有帮助解决这个问题。使用相同的代码(Seed() method)执行Sql命令非常有效,但这不是我想要使用的解决方案之一:

protected override void Seed(MyContext context)
{
    context
    .Database
    .ExecuteSqlCommand(
        "ALTER TABLE [dbo].[Data]  
            ADD CONSTRAINT [JsonData must be formatted as JSON] 
            CHECK  (IsJson([JsonData]) > 0)");
}

还有其他方法可以从Code First添加JSON Check Constraint吗?

4 个答案:

答案 0 :(得分:3)

根据接受的答案,您需要添加一个迁移。这是EF Core语法:

    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.Sql("ALTER TABLE dbo.Data ADD CONSTRAINT CK_Data_JsonData_MustBeJson CHECK (IsJson(JsonData) = 1);");
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.Sql("ALTER TABLE dbo.Applications DROP CONSTRAINT CK_Data_JsonData_MustBeJson;");
    }

答案 1 :(得分:1)

我认为EF不支持任何类型的CHECK约束。您唯一可以使用的是迁移。请参阅以下示例:Is it possible to add CHECK constraint with fluent API in EF7?

答案 2 :(得分:1)

在 EFCore 3+ 中,这现在是可能的。

注意:ISJSON 仅适用于 SQL Server 2016+

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
    foreach (var entityType in modelBuilder.Model.GetEntityTypes())
    {
        var tableIdentifier = StoreObjectIdentifier.Create(entityType, StoreObjectType.Table);
        foreach (var entityProperty in entityType.GetProperties())
        {
            if (entityProperty.PropertyInfo != null && Attribute.IsDefined(entityProperty.PropertyInfo, typeof(JsonAttribute), inherit: true))
            {
                var tableName = entityType.GetTableName();
                var columnName = entityProperty.GetColumnName(tableIdentifier.Value);
                modelBuilder.Entity(clrType).HasCheckConstraint(
                    name: $"CK_{tableName}_{columnName}_JSON",
                    sql: $"ISNULL(ISJSON({columnName}), 1) = 1"
                );
            }
        }
    }            
}

JsonAttribute 只是一个简单的标记,为了方便起见:

[AttributeUsage(AttributeTargets.Property)]
public class JsonAttribute : Attribute { }

用法:

public class MyEntity
{
    public int Id { get; set; }

    [Json]
    public string JsonData { get; set; }
}

使用属性的另一种可能替代方法是使用您自己的“约定”(例如,属性是字符串并具有“Json”前缀/后缀)

答案 3 :(得分:0)

我相信现在(EFCore 3+)你也可以使用 fluent api 来声明一个 json 检查约束。

protected override void OnModelCreating (ModelBuilder builder) {  
base.OnModelCreating (builder);

// gets the configurations
builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());

// adds cinstraint checks
builder.Entity<Settings>(e => e.HasCheckConstraint("CK_Set_JSONDocument_JSON","JSON_VALID(JSONDocument)" ));
}