如何在 Entity Framework 中为 JSON 添加检查约束?
How can I add a check constraint for JSON in Entity Framework?
为具有
的 table 字段添加 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
?
我认为 EF 不支持任何类型的 CHECK 约束。您唯一可以使用的是迁移。请参阅以下示例:
根据已接受的答案,您需要添加迁移。这是 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;");
}
我相信现在(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)" ));
}
在 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”prefix/suffix)
为具有
的 table 字段添加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
?
我认为 EF 不支持任何类型的 CHECK 约束。您唯一可以使用的是迁移。请参阅以下示例:
根据已接受的答案,您需要添加迁移。这是 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;");
}
我相信现在(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)" ));
}
在 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”prefix/suffix)