EF6缓存崩溃时的本地数据

时间:2016-01-06 19:29:35

标签: c# asp.net-mvc-5 entity-framework-6

我正在试图找出导致此错误的确切原因:

  

INSERT语句与FOREIGN KEY约束“FK_dbo.Draft_dbo.GameEvent_GameEventId”冲突。冲突发生在数据库“Azularis”,表“dbo.GameEvent”,列“Id”中。   声明已经终止。

现在的问题是,在我运行select语句的数据库中,表GameEvent为空。这是导致错误的代码

for (var i = 0; i < totalTeams / 2; i++)
{
    var game = new GameEvent
    {
        GameOrderNo = i + 1,
        EventId = eventId,
        RoundNo = 1
    };
    Db.GameEvents.Add(game);
}
if (await Db.SaveChangesAsync() > 0) //It crashes here
{
    Db.Drafts.Add(CreateDraft(teamIds.First(), game.Id, -1, 1));
    await Db.SaveChangesAsync() > 0
}

上面的逻辑是不完整的,因为我仍在开发这个,但崩溃发生在if (await Db.SaveChangesAsync() > 0)

现在,如果我删除数据库并运行它,它可以正常运行,记录保存并且没有错误。如果无论原因代码崩溃,我去删除记录并再次运行,我得到上述错误。

我注意到的是,如果我将鼠标悬停在Db.Draft上,并且我查看Local属性,它仍然有记录,它没有从缓存中转储它们,我假设它试图写两次相同的PK所以它崩溃了。

这是我的理论,我不理解,非常感谢任何帮助。

编辑: 我的另一个理论(我认为比第一个更可能)是草稿被缓存并且它正在尝试编写这些记录,并且当GameEvent为空时,它无法插入,因为没有主键可供引用。

因此,当代码崩溃时,如何强制它转储此缓存?在生产环境中,如果出现这种情况的原因,没有人能够插入更多数据。

我唯一能够解决上述错误的方法是暂时删除并重新创建数据库。

编辑2:

以下是我的复制方式: 我从新数据库开始,我运行一次。代码将在Db.Drafts.Add上草拟,因为teamId将为null。然后我回到数据库并截断草稿表,然后从GameEvent表中删除所有记录。

我再次运行代码,这次它在这个简单的测试场景中失败了:

var test = new GameEvent
{
   GameOrderNo = 1,
   EventId = new Guid("1e48bd5b-58ab-e511-a551-e03f497d18e0"),
   RoundNo = 1
};

Db.GameEvents.Add(test);
await Db.SaveChangesAsync();

编辑3:

架构是从以下代码生成的:

public class GameEvent
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }
    public Guid EventId { get; set; }
    public int GameOrderNo { get; set; }
    public int RoundNo { get; set; }
}

public class Draft
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }
    public Guid TeamId { get; set; }
    public Guid GameEventId { get; set; }
    public double Score { get; set; }
    public int Placement { get; set; }
    public virtual Team Team { get; set; }
    public virtual GameEvent GameEvent { get; set; }
}

1 个答案:

答案 0 :(得分:1)

这是因为Db的生命周期太长。 您应该从不使用静态上下文

首次创建DraftGameEvent时,EF首先将缓存中的新对象设为Added,保存之后,它们为Unchanged

现在您从数据库中删除所有内容并再次执行相同的操作。您创建的新实体将标记为Added,但与仍在缓存中的实体Unchanged有关联。现在EF只会为INSERT个实体发出Added个语句,而不会为Unchanged个实体发出var agent = new Agent({name: 'James', type: 'secret', id: 007}) 个语句。但插入的记录确实有FK指向您刚刚手动删除的记录。

根据您的描述,很难理解完全发生的事情,但如果您为每次数据库交互使用新的上下文,我相信您会遇到麻烦。