Contents

.Net Core Identity 帳號與角色關聯刪除

通常我們使用微軟建立好的資料表不會注意他有做那些關聯,功能方便,在使用的時候也需要注意一些事情,這邊特別記錄資料表關聯調整,設定上程式碼需要調整什麼。

Entity Framework Core 關聯刪除

Entity Framework Core 关联删除 - Sweet-Tang - 博客园

SQL 4種行為

在SQL Server中支持如下四種行為:

ON DELETE NO ACTION
默認行為,刪除主表數據行時,依賴表中的數據不會執行任何操作,此時會產生錯誤,並回滾DELETE語句。例如會產生下面的錯誤:

    DELETE 語句與 REFERENCE 約束"FK_Order Details_Orders_OrderID"衝突。該衝突發生於數據庫"Northwind_Test",表"dbo.Order Details", column 'OrderID'。
    語句已終止。
ON DELETE CASCADE
刪除主表數據行時,依賴表的中數據行也會同步刪除。
ON DELETE SET NULL
刪除主表數據行時,將依賴表中數據行的外鍵更新為NULL。為了滿足此約束,目標表的外鍵列必須可為空值。
ON DELETE SET DEFAULT
刪除主表數據行時,將依賴表的中數據行的外鍵更新為默認值。為了滿足此約束,目標表的所有外鍵列必須具有默認值定義;如果外鍵可為空值,並且未顯式設置默認值,則將使用NULL作為該列的隱式默認值。

簡單介紹了數據庫中行為後,我們來著重介紹 EF Core 中的關聯實體的行為。

預設 Identity 資料表動作(級聯刪除 CasCade)

Identity 資料表動作預設為級聯刪除(CasCade) ,這邊要注意 SQL Server 預設為 NoAction,Identity 資料表預設不知道為什麼做級聯刪除 (CasCade)。但我們可以手動改掉他。

下圖是看資料表建立的Schema,可以看外鍵設定。

https://i.imgur.com/giwTkOd.png

https://i.imgur.com/PgLoXCx.png

這邊可以直接測試看看

GIT: 刪除使用者 · malagege/NetCoreAuthSample@01b8e0a

防止連同刪除方法

GIT: 角色防止連動刪除用戶關連資料 · malagege/NetCoreAuthSample@0a6a78f

全部外鍵設定 Restrict
AppContextDb.cs

1
2
3
4
5
6
            // base.OnModelCreating(modelBuilder);
            var foreignKeys = modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys());
            foreach (var foreignKey in foreignKeys)
            {
               foreignKey.DeleteBehavior = DeleteBehavior.Restrict;
            }

powershell

1
Add-Migration DeleteBehaviorRestrict

不知道是不是新版關係,我們這邊會出錯

1
The entity type 'IdentityUserLogin<string>' requires a primary key to be defined. If you intended to use a keyless entity type, call 'HasNoKey' in 'OnModelCreating'. For more information on keyless entity types, see https://go.microsoft.com/fwlink/?linkid=2141943.

後來發現少了一句base.OnModelCreating(modelBuilder);,參考c# - The entity type ‘IdentityUserLogin<string>’ requires a primary key to be defined - Stack Overflow

AppContextDb.cs

1
2
3
4
5
6
            base.OnModelCreating(modelBuilder);
            var foreignKeys = modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys());
            foreach (var foreignKey in foreignKeys)
            {
               foreignKey.DeleteBehavior = DeleteBehavior.Restrict;
            }

Powershell 以下指令就會成功了

1
Add-Migration DeleteBehaviorRestrict

其他相關IdentityASP.NET Core 中的模型自訂 | Microsoft Docs

https://i.imgur.com/oXE36It.png

刪除含有帳號的角色會看到Exception。

https://i.imgur.com/pxhg7Df.png

指定 Identity Table 外來鍵設定

上面寫法我覺得程式很少,不能做到特定篩選,我怕日後這些程式碼會不會影響我建立關聯的Entity,所以我找相關可以取代指定 Entity方法。後來拼拼湊湊組成下面這個。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
            var foreignKeys = modelBuilder.Entity<IdentityUserRole<string>>().Metadata.GetForeignKeys();
            foreach (var foreignKey in foreignKeys)
            {
                foreignKey.DeleteBehavior = DeleteBehavior.Restrict;
            }

            foreignKeys = modelBuilder.Entity<IdentityUserToken<string>>().Metadata.GetForeignKeys();
            foreach (var foreignKey in foreignKeys)
            {
                foreignKey.DeleteBehavior = DeleteBehavior.Restrict;
            }

            foreignKeys = modelBuilder.Entity<IdentityUserClaim<string>>().Metadata.GetForeignKeys();
            foreach (var foreignKey in foreignKeys)
            {
                foreignKey.DeleteBehavior = DeleteBehavior.Restrict;
            }

            foreignKeys = modelBuilder.Entity<IdentityUserLogin<string>>().Metadata.GetForeignKeys();
            foreach (var foreignKey in foreignKeys)
            {
                foreignKey.DeleteBehavior = DeleteBehavior.Restrict;
            }

            foreignKeys = modelBuilder.Entity<IdentityRoleClaim<string>>().Metadata.GetForeignKeys();
            foreach (var foreignKey in foreignKeys)
            {
                foreignKey.DeleteBehavior = DeleteBehavior.Restrict;
            }

我還是不建議用上面方法,反思為什麼不用程式去查詢判斷 IdentityUserRole 相關資料表有沒有料?透過程式去阻擋?這都是可以解決的。

參考來源