ArK*_*rKi 2 c# postgresql npgsql entity-framework-core
我有以下具有必需属性的类,并且遇到通过级联删除删除依赖属性的问题.
public class City
{
[Key]
public int Id {get; private set; }
[Required]
public ZipCode ZipCode { get; private set; }
}
public class ZipCode
{
[Key]
public int Id { get; private set; }
[Required]
public string Zip { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)
如果我尝试加载城市以使用以下代码删除它:
City toDelete = db.CitySet.Where(c => c.Id == myCityReference.Id).FirstOrDefault();
db.CitySet.Remove(toDelete);
db.SaveChanges();
Run Code Online (Sandbox Code Playgroud)
我得到一个Microsoft.EntityFrameworkCore.DbUpdateException,其内在的例外是Npgsql.PostgresException: 23503: Update or delete on table "..." violates foreign key constraint..
但是,如果我在上面添加一个include语句,那就是:
City toDelete = db.CitySet.Include(c => c.ZipCode)
.Where(c => c.Id == myCityReference.Id).FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)
然后删除成功删除城市和邮政编码.但是,根据EFCore 文档,将设置Required关系以Cascade删除功能.为什么这不会发生?我正在使用Entity Framework Core v1.1.1和Npgsql v3.2.2.
以下是从您的模型生成的迁移:
migrationBuilder.CreateTable(
name: "ZipCodes",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
Zip = table.Column<string>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ZipCodes", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Cities",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
ZipCodeId = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Cities", x => x.Id);
table.ForeignKey(
name: "FK_Cities_ZipCodes_ZipCodeId",
column: x => x.ZipCodeId,
principalTable: "ZipCodes",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Cities_ZipCodeId",
table: "Cities",
column: "ZipCodeId");
Run Code Online (Sandbox Code Playgroud)
(它适用于Sql Server,但除了一些特定的标识列注释外,对于其他数据库类型应该是相同的)
如您所见,FK是在启用级联删除的情况下创建的.但是,FK列在City表中并引用该ZipCode表.这意味着ZipCode是主体,City是依赖.所以删除一个ZipCode将级联删除City,而不是相反.
此外,ZipCodeId列上没有唯一约束/索引,这表示EF Core假设one-to-many关系(ZipCode一对多City).
如果您希望它以相反的方向级联,那么您需要ZipCode使用以下流畅的配置将FK列放在表中:
modelBuilder.Entity<City>()
.HasOne(e => e.ZipCode)
.WithOne()
.HasForeignKey<ZipCode>("CityId")
.OnDelete(DeleteBehavior.Cascade);
Run Code Online (Sandbox Code Playgroud)
现在迁移看起来像这样:
migrationBuilder.CreateTable(
name: "Cities",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn)
},
constraints: table =>
{
table.PrimaryKey("PK_Cities", x => x.Id);
});
migrationBuilder.CreateTable(
name: "ZipCodes",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
CityId = table.Column<int>(nullable: true),
Zip = table.Column<string>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ZipCodes", x => x.Id);
table.ForeignKey(
name: "FK_ZipCodes_Cities_CityId",
column: x => x.CityId,
principalTable: "Cities",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_ZipCodes_CityId",
table: "ZipCodes",
column: "CityId",
unique: true);
Run Code Online (Sandbox Code Playgroud)
即级联是从City到ZipCode和的关系one-to-one(注意唯一索引).
现在,我不确定这里的真正意图是什么.但是确保数据库级联删除是定向的 - 从引用表到引用表.
| 归档时间: |
|
| 查看次数: |
678 次 |
| 最近记录: |