【问题标题】:EF set foreign key to null on parent deleteEF在父删除时将外键设置为null
【发布时间】:2014-12-09 08:37:12
【问题描述】:

我有两个模型 Team 和 Player

    public class Player
    {
            public int Id { get; set; }
    }

    public class FootballPlayer : Player
    {
        public int? TeamId { get; set; }

        public virtual FootballTeam Team { get; set; }
    }

    public class BasketballPlayer : Player
    {
        public int? TeamId { get; set; }

        public virtual BasketballTeam Team { get; set; }
    }

    public class BasketballTeam : Team
    {
        public int Id { get; set; }
        public virtual List<BasketballPlayer> Players { get; set; }
    }

public class FootballTeam : Team
    {
        public int Id { get; set; }
        public virtual List<FootballPlayer > Players { get; set; }
    }

这是一个配置

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {

        modelBuilder.Entity<FootballPlayer>().HasOptional(r => r.Team)
        .WithMany(a => a.Players)
        .HasForeignKey(b => new { b.TeamId })
        .WillCascadeOnDelete(false);

        modelBuilder.Entity<BasketballPlayer>().HasOptional(r => r.Team)
        .WithMany(a => a.Players)
        .HasForeignKey(b => new { b.TeamId })
        .WillCascadeOnDelete(false);

        base.OnModelCreating(modelBuilder);
    }

我使用的是 EF Code First,我想在我删除团队时,不应该删除玩家,只有将 TeamId 设置为 null。如何做到这一点?

【问题讨论】:

  • 您在建立关系时是否探索过使用 WillCascadeOnDelete(false)?
  • 我现在工作,但是当我想检索团队时,即使玩家属于团队,它也不再检索玩家了
  • 我已经添加了我添加并为我工作的配置。我可以删除,请参阅数据库中 TeamId 的 Null。然后我查询了有Null的项目,一切正常。试一试。
  • 查看我的更新。该脚本应允许您删除团队并将 TeamId 设置为 null。我已经对其进行了测试,可以与您的实体一起使用。

标签: .net asp.net-mvc database entity-framework constraints


【解决方案1】:

这是我为您的实体定义的配置:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Player>().HasOptional(r => r.Team)
            .WithMany(a => a.Players)
            .HasForeignKey(b => new { b.TeamId })
            .WillCascadeOnDelete(false);

        base.OnModelCreating(modelBuilder);
    }

更新

以上配置适用于您的原始实体,即简单的一对多关系(团队->玩家)。新实体涉及继承,这令人惊讶地消除了上述配置的影响。

对于新实体,配置仍然相同(HasOptional 和 CascadeOnDelete),但是,它不允许删除任何玩家正在使用的团队。它抛出

{"DELETE 语句与 REFERENCE 约束冲突 \"FK_dbo.FootballPlayers_dbo.FootballTeams_TeamId\"。冲突 发生在数据库“EF6Testing.StudentContext”,表中 \"dbo.FootballPlayers\",列 'TeamId'。\r\n该语句已 终止。”}

这是由于 EF 在一对多关系案例中添加的约束 ([FK_dbo.FootballPlayers_dbo.FootballTeams_TeamId])。但是,我不清楚的是,在 Team -> Players 案例中添加了相同的约束,而 EF 没有“强制执行外键约束”。

那么当实体具有继承层次结构时,为什么 EF 不允许删除团队???

好的,让我们把这个谜团留给 EF 专家来解决。

处理此问题的解决方案(可能的解决方案之一)是,您必须执行 SQL 脚本来删除和创建约束。此脚本将设置外键为空。

我有兴趣找到上述问题的答案,以及 EF(5 或 6 或更高版本)中是否有更好的解决方案来处理这种情况。

USE [@DatabaseName]
GO

ALTER TABLE [dbo].[FootballPlayers] DROP CONSTRAINT [FK_dbo.FootballPlayers_dbo.FootballTeams_TeamId]
GO

ALTER TABLE [dbo].[FootballPlayers]  WITH CHECK ADD  CONSTRAINT [FK_dbo.FootballPlayers_dbo.FootballTeams_TeamId] FOREIGN KEY([TeamId])
REFERENCES [dbo].[FootballTeams] ([Id]) on delete set null
GO

ALTER TABLE [dbo].[FootballPlayers] CHECK CONSTRAINT [FK_dbo.FootballPlayers_dbo.FootballTeams_TeamId]
GO

【讨论】:

  • 现在,当我再次尝试删除有球员的球队时,我得到了这个异常:“DELETE 语句与 REFERENCE 约束“FK_dbo.Players_dbo.Teams_TeamId”冲突。冲突发生在数据库中“SportsStats”,表“dbo.Players”,列“TeamId”。语句已终止。”
  • @user2412672 - 你能显示你的配置吗,你必须设置 HasOptional 关系,如我的回答所示。使用上述配置,我可以删除团队。
  • modelBuilder.Entity().HasOptional(r => r.Team) .WithMany(a => a.Players) .HasForeignKey(b => new { b.TeamId }) 。 WillCascadeOnDelete(false);
  • 检索您应该首先使用 System.Data.Entity 添加的播放器;并在查询中执行以下操作: var query=db.Teams.Include(p=>p.Players).ToList();
  • @user2412672 - 啊,新模型需要相应地设置关系。我建议您在 OP 中添加配置、上下文以及用于执行检索或删除的代码。其他人会更快地提供帮助。
猜你喜欢
  • 2021-03-20
  • 2017-10-07
  • 1970-01-01
  • 1970-01-01
  • 2020-12-02
  • 1970-01-01
  • 2013-03-22
  • 2012-03-30
  • 2021-10-28
相关资源
最近更新 更多