EF6崩溃时缓存本地数据
本文关键字:数据 缓存 崩溃 EF6 | 更新日期: 2023-09-27 18:29:18
我正试图弄清楚到底是什么导致了这个错误:
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,所以它崩溃了。
这是我的理论,我不理解,任何帮助都是非常感激的。
编辑:我的另一个理论(我认为这比第一个更有可能)是,Draft被缓存了,它正在尝试写入这些记录,由于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; }
}
这是因为Db
的寿命太长您应该永远不要使用静态上下文。
当您第一次创建Draft
和GameEvent
时,EF首先将缓存中的新对象作为Added
,保存后即为Unchanged
。
现在,您可以从数据库中删除所有内容,然后再次执行相同的操作。您创建的新实体将标记为Added
,但与仍在缓存中作为Unchanged
的实体有关联。现在EF将只为Added
实体发出INSERT
语句,而不为Unchanged
实体发出。但是插入的记录确实具有指向您刚刚手动删除的记录的FK。
根据您的描述,很难理解到底发生了什么,但我相信,如果您为每次数据库交互使用新的上下文,您将不会遇到麻烦。