【问题标题】:EF Core delete data in many to many relationshipEF Core 删除多对多关系中的数据
【发布时间】:2020-03-23 19:48:20
【问题描述】:

我有以下表格:

public class Team 
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required]
    public string Name { get; set; }

    public virtual ICollection<UserTeam> UserTeams { get; set; }
}

public class User
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required]
    public string Name { get; set; }

    public virtual ICollection<UserTeam> UserTeams { get; set; }
}

public class UserTeam
{
    public long UserId { get; set; }
    public User User { get; set; }

    public long TeamId { get; set; }
    public Team Team { get; set; }
}

多对多关系在上下文中定义:

modelBuilder.Entity<UserTeam>()
    .HasKey(bc => new { bc.UserId, bc.TeamId });

modelBuilder.Entity<UserTeam>()
    .HasOne(bc => bc.User)
    .WithMany(b => b.UserTeams)
    .HasForeignKey(bc => bc.UserId)
    .OnDelete(DeleteBehavior.Restrict);

modelBuilder.Entity<UserTeam>()
    .HasOne(bc => bc.Team)
    .WithMany(c => c.UserTeams)
    .HasForeignKey(bc => bc.TeamId)
    .OnDelete(DeleteBehavior.Restrict);

我正在尝试使用以下代码从团队中删除一些用户:

public async Task RemoveUsersFromTeam(int teamId, List<long> users)
{
    Team existingTeam = await dbContext.Team.Include(x => x.UserTeams).FirstOrDefaultAsync(x => x.Id == teamId);
    foreach (var user in users)
    {
        existingTeam.UserTeams.Remove(new UserTeam { UserId = user });
    }

    await dbContext.SaveAsync();
}

但是这个查询并没有删除我通过的用户。有谁知道为什么会这样?

【问题讨论】:

  • 你有.OnDelete(DeleteBehavior.Restrict);
  • 是的,这是在您删除父级(团队或用户)时使用的
  • 您不必先将UserTeam 附加到上下文中吗?
  • 但这不是一个断开连接的场景。首先我查询团队(已附加)然后我修改它。不应该跟踪变化吗?
  • 您正在创建 UserTeam,因此您需要让 EF 知道它已经存在,例如将其附加到图表中。至少在 EF 6 中。见stackoverflow.com/questions/2471433/…

标签: c# .net-core entity-framework-core ef-core-2.2


【解决方案1】:

您可以使用 new 和 attach 方法按 Id 删除对象,或者通过传递实际实体。

传递实体

public async Task RemoveUsersFromTeam(int teamId, List<long> userIds)
{
    Team existingTeam = await dbContext.Team.Include(x => x.UserTeams).FirstOrDefaultAsync(x => x.Id == teamId);
    foreach (var userId in userIds)
    {
        var userTeam = existingTeam.UserTeams.FirstOrDefault(x => x.UserId == userId);
        if(userTeam != null)
        {
            existingTeam.UserTeams.Remove(userTeam);
        }
    }

    await dbContext.SaveAsync();
}

按 ID 删除

public async Task RemoveUsersFromTeam(int teamId, List<long> userIds)
{
    Team existingTeam = await dbContext.Team.FirstOrDefaultAsync(x => x.Id == teamId);
    foreach (var userId in userIds)
    {
        var userTeam = new UserTeam { UserId = userId });
        dbContext.UserTeams.Attach(userTeam);
        existingTeam.UserTeams.Remove(userTeam);
    }

    await dbContext.SaveAsync();
}

选项 2 不需要从数据库中选择 UserTeams,在这方面效率会稍高一些。但是选项一可能更容易理解。您应该选择最适合您的情况。

我个人更喜欢选项二,因为 include 会选择整个实体,在某些情况下可能会超出必要的范围。

【讨论】:

  • 相同。选项2要好得多。但是,当我尝试做同样的事情但使用existingTeam.UserTeams.Add(userTeam) 方法时,条目不会插入到 db
  • 添加时,您不应附加实体,因为这表示它已经存在并发出更新而不是插入。
  • 检查您在上面创建的私人聊天
猜你喜欢
  • 2021-03-30
  • 1970-01-01
  • 2021-10-11
  • 1970-01-01
  • 1970-01-01
  • 2017-04-17
  • 2018-06-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多