所以,在我的模型中我有一个Player类和一个Game类,Game有2个必需的玩家,如下:(以及其他一些我没有在这里包含的字段)
public class Game
{
public Player Player1 { get; set; }
[Required]
public int Player1Id { get; set; }
public Player Player2 { get; set; }
[Required]
public int Player2Id { get; set; }
}
尝试将此模型迁移到数据库时,出现以下错误:
在表'Games'上引入FOREIGN KEY约束'FK_dbo.Games_dbo.Players_Player2Id'可能会导致循环或多个级联路径。指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束。
(this stackoverflow question的答案很好地解释了为什么我会收到此错误。)
为避免此错误,我添加了以下流畅的API代码:
modelBuilder.Entity<Game>()
.HasRequired(c => c.Player1)
.WithMany()
.HasForeignKey(c => c.Player1Id)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Game>()
.HasRequired(c => c.Player2)
.WithMany()
.HasForeignKey(c => c.Player2Id)
.WillCascadeOnDelete(false);
我现在遇到的问题是,当我尝试删除播放器时,其ID在一个或多个游戏中被引用。
操作失败:无法更改关系,因为一个或多个外键属性不可为空。当对关系进行更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。
如果我正确理解了这个错误,我会收到这个错误,因为游戏失败的一个外键约束(级联删除是假的,所以游戏不会随播放器一起被删除。相反,Player1Id(或者Player2Id)设置为null,这会打破约束,因为它们都是必需的且不可为空的)
所以我尝试在Seed()方法中创建this SO question中的触发器。
context.Database.ExecuteSqlCommand("CREATE TRIGGER Game_Player_Del on dbo.Players instead of delete as " +
"set nocount on " +
"delete from dbo.Games where Player1Id in (select Id from deleted) or " +
"Player2Id in (Select Id from deleted) " +
"delete from dbo.Players where Id in (select Id from deleted)");
当我检查我的数据库时,触发器确实被添加,但它似乎不起作用,因为我仍然得到与添加触发器之前相同的错误。
那么,我应该怎样做才能使这项工作按预期进行? (删除玩家也会删除相关的游戏,删除游戏不会删除玩家)
编辑:我想到的一个可能的解决方案是在我的控制器中编辑删除方法,首先获得Player1Id或Player2Id等于Player.Id的所有游戏,删除那些然后删除播放器,但是(我认为)删除播放器时我不应该担心游戏,实体框架应该为我做这个。
编辑2 :(回应usr的评论)这是我的删除代码:
控制器:
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
repo.deletePlayer(id);
return RedirectToAction("Index");
}
回购:
public void deletePlayer(int id)
{
using (var context = new TennisContext())
{
player = context.Players.Find(id);
context.Entry(player).State = EntityState.Deleted;
context.SaveChanges();
}
}
编辑3:在删除播放器之前,我设法通过查询和删除受影响的游戏来使其工作。
回购代码:
public void deletePlayer(int id)
{
using (var context = new TennisContext())
{
player = context.Players.Find(id);
List<Game> playerGames = context.Games.Where(g => g.Player1Id == id || g.Player2Id == id).ToList();
foreach (Game g in playerGames)
{
context.Entry(g).State = EntityState.Deleted;
}
context.Entry(player).State = EntityState.Deleted;
context.SaveChanges();
}
}
答案 0 :(得分:1)
使用Entity Framework代码手动删除游戏。查询受影响的游戏并将其传递给相应的删除方法(例如Entry(player).State = EntityState.Deleted
内容或任何其他等效内容。)
由于您无法使用自动级联,请手动执行此操作。
答案 1 :(得分:0)
两个玩家ID都有[必需]属性。如果您尝试删除玩家会发生什么?也许我的其中一个玩家应该可以为空?同意触发的评论 - 不适合您。