EF6 多对多不能删除
Posted
技术标签:
【中文标题】EF6 多对多不能删除【英文标题】:EF6 Many-to-many can not delete 【发布时间】:2022-01-08 22:44:33 【问题描述】:我使用以下代码使用 EF6 核心创建了表。
问题是, UserA 、 UserB 创建并分配了不同的声明。完全没有问题。分配现有声明时(例如,为 UserB 分配了 UserA 的声明 --> [tying to do] 删除 UserB 的声明并将 UserB 的主题更改为 UserA 的主题)然后我将通过 subjectId 删除 UserB 的声明,这将创建主要UserUserClaims 表中的关键重复问题 bcos SubjectId 和 ClaimId 已经存在
public class User
[Key]
public Guid UserId get; set;
[MaxLength(200)]
public string Username get; set;
[Required]
public Guid Subject get; set;
public ICollection<UserClaim> Claims get; set; = new List<UserClaim>();
public List<UserClaimRelation> UserClaimRelations get; set;
public class UserClaim
[Key]
public Guid UserClaimId get; set;
[MaxLength(250)]
[Required]
public string Type get; set;
[Required]
public Guid Subject get; set;
[MaxLength(250)]
[Required]
public string Value get; set;
public ICollection<User> Users get; set;
public List<UserClaimRelation> UserClaimRelations get; set;
public class UserClaimRelation
public Guid UserClaimId get; set;
public UserClaim Claim get; set;
public Guid UserSubject get; set;
public User User get; set;
public class MyDbContext: DbContext
public DbSet<User> Users get; set;
public DbSet<UserClaim> UserClaims get; set;
protected override void OnModelCreating(ModelBuilder modelBuilder)
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>()
.HasMany(p => p.Claims)
.WithMany(p => p.Users)
.UsingEntity<UserClaimRelation>(
j => j
.HasOne(pt => pt.Claim)
.WithMany(t => t.UserClaimRelations)
.HasPrincipalKey(f => f.UserClaimId),
j => j.HasOne(p => p.User)
.WithMany(t => t.UserClaimRelations)
.HasPrincipalKey( t => t.Subject),
j => j.HasKey( t => new t.UserClaimId, t.UserSubject)
);
我正在尝试按 SubjectId 删除声明
public async Task<bool> DeleteUserClaimsBySubjectAsync(Guid subject)
if (subject == Guid.Empty)
throw new ArgumentNullException(nameof(subject));
var claims = await _context.UserClaims
.Where(x => x.Subject == subject).ToListAsync();
foreach (var claim in claims)
_context.UserClaims.Remove(claim);
//_context.UserClaims.RemoveRange(claims);
return (await _context.SaveChangesAsync() > 0);
在 DeleteUserClaimsBySubjectAsync 中删除声明时,我收到以下错误
SqlException:违反主键约束“PK_UserClaimRelation”。无法在对象“dbo.UserClaimRelation”中插入重复键。重复键值为 (13229d33-99e0-41b3-b18d-4f72127e3971, 8acbbd40-1608-41f2-de59-08d9b58b83d3)。
SQL Profiler 查询
exec sp_executesql N'SET NOCOUNT ON;
INSERT INTO [UserClaimRelation] ([UserClaimId], [UserSubject])
VALUES (@p0, @p1),
(@p2, @p3),
(@p4, @p5),
(@p6, @p7),
(@p8, @p9);
DELETE FROM [UserClaims]
WHERE [UserClaimId] = @p10 AND [ConcurrencyStamp] = @p11;
SELECT @@ROWCOUNT;
DELETE FROM [UserClaims]
WHERE [UserClaimId] = @p12 AND [ConcurrencyStamp] = @p13;
SELECT @@ROWCOUNT;
DELETE FROM [UserClaims]
WHERE [UserClaimId] = @p14 AND [ConcurrencyStamp] = @p15;
SELECT @@ROWCOUNT;
DELETE FROM [UserClaims]
WHERE [UserClaimId] = @p16 AND [ConcurrencyStamp] = @p17;
SELECT @@ROWCOUNT;
DELETE FROM [UserClaims]
WHERE [UserClaimId] = @p18 AND [ConcurrencyStamp] = @p19;
SELECT @@ROWCOUNT;
',N'@p0 uniqueidentifier,@p1 uniqueidentifier,@p2 uniqueidentifier,@p3 uniqueidentifier,@p4 uniqueidentifier,@p5 uniqueidentifier,@p6 uniqueidentifier,@p7 uniqueidentifier,@p8 uniqueidentifier,@p9 uniqueidentifier,@p10 uniqueidentifier,@p11 nvarchar(4000),@p12 uniqueidentifier,@p13 nvarchar(4000),@p14 uniqueidentifier,@p15 nvarchar(4000),@p16 uniqueidentifier,@p17 nvarchar(4000),@p18 uniqueidentifier,@p19 nvarchar(4000)',
@p0='6203BBC3-BD52-4E32-3DDD-08D9B86AB745',@p1='D860EFCA-22D9-47FD-8249-791BA61B07C7',
@p2='80B958C5-FF44-400F-3DDE-08D9B86AB745',@p3='D860EFCA-22D9-47FD-8249-791BA61B07C7',
@p4='A844CB59-5A00-488A-3DDF-08D9B86AB745',@p5='D860EFCA-22D9-47FD-8249-791BA61B07C7',@p6='794AB806-3215-45AF-3DE0-08D9B86AB745',@p7='D860EFCA-22D9-47FD-8249-791BA61B07C7',@p8='80EFF0DF-AE56-419A-3DE1-08D9B86AB745',@p9='D860EFCA-22D9-47FD-8249-791BA61B07C7',@p10='1A48CF6E-E1CD-4042-3DE4-08D9B86AB745',@p11=N'742674d8-3c59-4be4-ac09-38c6804acb66',@p12='258ABD95-6B2A-45CC-3DE6-08D9B86AB745',@p13=N'd206316a-71af-46b7-92e4-bddca669ad87',@p14='4FB1D2E3-18BE-4AFC-3DE3-08D9B86AB745',@p15=N'3eb17fb7-998b-47e1-a97f-3640cbd82b7a',@p16='6C2B9A18-5C8F-4068-3DE5-08D9B86AB745',@p17=N'415b2cc1-b50a-4ec8-872d-13b6342dcd33',@p18='951CEEA6-D057-4588-3DE2-08D9B86AB745',@p19=N'3dfd76dd-d515-4daa-893c-f1ae97aa063a'
【问题讨论】:
您是如何填充这些表格的?看起来 EF 想要在您删除的过程中填充连接表 - 您是否以某种方式手动填充它?如果是这样,请尝试使用 EF 分配声明,加载用户并添加声明。然后保存后,尝试删除。 在源代码中,您可以看到用于填充关系的 UserClaimRelation 和 MyDbContext 代码。从 UserClaims 中删除时,我不明白为什么要插入 UserClaimRelation,对此有什么想法吗? 不要加入.HasPrincipalKey( t => t.Subject)
而是加入 .HasPrincipalKey( t => t.UserClaimId) - 这应该会有所帮助。您仍然可以通过搜索适当的主题来删除。
对不起,我没明白你的意思
【参考方案1】:
好的,因此您需要在这里建立多对多关系 - 多个用户可以有多个不同的声明,并且可以将多个声明分配给多个用户。
所以首先 - User
s:
public class User
[Key]
public Guid UserId get; set;
[MaxLength(200)]
public string Username get; set;
[Required]
public Guid Subject get; set;
public ICollection<UserClaim> Claims get; set; = new List<UserClaim>();
那么,UserClaim
s
public class UserClaim
[Key]
public Guid UserClaimId get; set;
[MaxLength(250)]
[Required]
public string Type get; set;
[Required]
public Guid Subject get; set;
[MaxLength(250)]
[Required]
public string Value get; set;
public ICollection<User> Users get; set;
请注意,以上任何内容都没有指向UserClaimRelation
的导航属性。事实上,我们将这个UserClaimRelation
完全删除为一个单独的实体模型——这个例子不需要它。如果你真的想要,你可以映射它,但让我们专注于完成这项工作。
现在,关系设置:
protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity<User>()
.HasMany(x => x.Claims)
.WithMany(x => x.Users)
.UsingEntity<Dictionary<string, object>>(
"UserClaimRelation",
x => x.HasOne<User>().WithMany(),
x => x.HasOne<UserClaim>().WithMany(),
x => x.ToTable("UserClaimRelation"));
现在,在更新/重新创建/重新应用迁移到数据库之后(取决于您的处理方式),您应该能够按主题删除声明,而无需修改您的 DeleteUserClaimsBySubjectAsync
方法。
这应该设置所有内容并创建中间表。验证这段代码,我是从内存中输入的
【讨论】:
请检查我下面的会话作为答案。您的解决方案不起作用。请注意,我正在用 UserB 更新 userA Subject,所以 userA 和 UserB 都有 same subject 好的,但这应该不是问题,因为主题不是任何地方的键或外键,对吧?因此它可以被复制。如果您将主题用作外键,则会导致问题,这在我的示例中不应该发生。学科,至少在理论上只是正常的必填字段。此外,它与加入表 (UserClaimRelation
) 没有任何关系 - 按照惯例,它不在那里使用,只有 ID 存储在那里。可能是您没有应用迁移或类似的东西吗?数据库表已经存在,代码的变化没有反映在数据库中?【参考方案2】:
我应用了代码。创建的表格如下图所示。但是当我尝试用 userB 的主题更新用户 A 的主题(用户 B 的相同声明)时,我收到以下错误
更新
SqlException:违反主键约束“PK_UserClaimRelation”。无法在对象“dbo.UserClaimRelation”中插入重复键。重复键值为 (bd7eb87f-2a5f-4921-758e-08d9b97d3121, 13229d33-99e0-41b3-b18d-4f72127e3971)。因为它试图插入 UserClaimRelation,与我最初给出的探查器查询相同。
【讨论】:
以上是关于EF6 多对多不能删除的主要内容,如果未能解决你的问题,请参考以下文章