2017-03-28 53 views
2

我有以下類與必需的屬性,並遇到問題刪除從屬性通過級聯刪除。爲什麼我的Required屬性沒有在實體框架核心中級聯刪除?

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; } 
} 

如果我嘗試加載城市使用下面的代碼將其刪除:

City toDelete = db.CitySet.Where(c => c.Id == myCityReference.Id).FirstOrDefault(); 
db.CitySet.Remove(toDelete); 
db.SaveChanges(); 

我得到了一個Microsoft.EntityFrameworkCore.DbUpdateException,其內部異常是Npgsql.PostgresException: 23503: Update or delete on table "..." violates foreign key constraint.

不過,如果我添加一個包含語句上面,那就是:

City toDelete = db.CitySet.Include(c => c.ZipCode) 
    .Where(c => c.Id == myCityReference.Id).FirstOrDefault(); 

然後成功地刪除將同時刪除城市和郵政編碼。但是,根據EFCore docs,所需的關係將被設置爲Cascade刪除功能。爲什麼這不會發生?我正在使用實體框架核心v1.1.1和Npgsql v3.2.2。

+0

確定'Required'屬性對導航屬性有效嗎?你可以顯示其他實體和流利的配置嗎? –

+0

嗨@IvanStoev,這是一個很好的問題,我不知道'Required'是否對導航屬性生效?另一個實體只是一個郵政編碼的字符串。目前沒有Fluent配置。 – ArKi

+0

仍然很高興看到它。例如,它是否包含反轉\ navigation屬性,如'public City City {get;組; }'。它對FK使用共享PK嗎?哪個實體包含數據庫中的FK?等等。如果您發佈它,我可以將它們放在我的測試EF Core上下文中,並查看遷移說的內容。 –

回答

4

這裏是你的模型生成的遷移:

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"); 

(這是對於SQL Server,但除了一些特定的標識列的註解,它應該是其他數據庫類型相同)

正如你可以看到,FK是在級聯刪除打開的情況下創建的。但是,FK列在City表中,並且引用ZipCode表。這意味着ZipCode是委託人,City是委託人。因此,刪除ZipCode將級聯刪除City,而不是反之。

此外,ZipCodeId列上沒有唯一約束/索引,表示EF Core假設爲one-to-many關係(一個ZipCode至多個City)。

如果你想讓它級聯在相反的方向,那麼你就需要使用以下流利的配置把FK列在ZipCode表:

modelBuilder.Entity<City>() 
    .HasOne(e => e.ZipCode) 
    .WithOne() 
    .HasForeignKey<ZipCode>("CityId") 
    .OnDelete(DeleteBehavior.Cascade); 

現在遷移看起來是這樣的:

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); 

即級聯是從CityZipCode,關係是one-to-one(注意唯一索引)。

現在,我不確定這裏真正的意圖是什麼。但是肯定數據庫級聯刪除是定向的 - 從引用表到引用表。

相關問題