【问题标题】:Entity Framework 6 and SQLite - cannot create entry with PK of entry deleted before实体框架 6 和 SQLite - 无法创建条目 PK 之前删除的条目
【发布时间】:2016-01-17 14:17:38
【问题描述】:

我正在使用 Entity Framework 6 和 SQLite 数据库 (System.Data.SQLite.EF6),但删除后我无法立即创建具有相同主键的条目。例如:

我的实体模型:

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

  public int Name { get; set; }
}

步骤:

1) 我将此实体 person1(Id = 1)的实例插入到我的人员表中。

using (var context = new MyDbContext())
{
   context.Create(person1);
   await context.SaveChangesAsync();
}

2) 读完一些书后,我清除了整个 Persons 表:

using (var context = new MyDbContext())
{
   await context.Database.ExecuteSqlCommandAsync(string.Format("DELETE FROM `PersonModels`"));
   await context.SaveChangesAsync();
}

3) 我尝试添加与第一步中的条目具有相同主键的条目:person2 (with Id = 1)

using (var context = new MyDbContext())
{
   context.Create(person2);
   await context.SaveChangesAsync();
}

但在第 3 步中,SaveChangesAsync() 失败并显示

System.InvalidOperationException:对数据库的更改已成功提交,但在更新对象上下文时出错。 ObjectContext 可能处于不一致的状态。内部异常消息:保存或接受更改失败,因为多个“DbModels.PersonModel”类型的实体具有相同的主键值。

当我在清除表后添加一些其他条目(使用不同的主键)然后从第一步添加条目时,它工作正常并且两个条目都被保存,没有例外。

我直接在创建新条目之前添加了一个断点(在清除表之后)并通过外部工具检查了 Persons 表并且表为空(因此没有 id = 1 的条目)。

更新: 扩展 DbContexte + 我的 Create 方法的实现:

    public DbSet<PersonModel> Persons { get; set; }

    public T Create<T>(T entity)
        where T : class
    {
        try
        {
            GetDbSetForType<T>().Add(entity);
            return entity;
        }
        catch (Exception ex)
        {
            return default(T);
        }
    }

    private DbSet<T> GetDbSetForType<T>()
        where T : class
    {
        var type = typeof(T);

        if (type == typeof(PersonModel)) return Persons as DbSet<T>;
        //...my other types
        throw new Exception("Type not found in db");
    }    

【问题讨论】:

  • context.Create(person2) - 这是你自己的方法吗?因为我不记得EF有它。如果是这样 - 你能展示一下吗?
  • @Toddams 哦,对不起,我在问题中添加了我的 Create 方法的正文
  • 如果你从 PersonModels 中删除所有条目,你可以改用这个:await context.Database.ExecuteSqlCommandAsync(string.Format("TRUNCATE TABLE 'PersonModels'"));这对你有用吗?
  • @LocEngineer SQLite 不支持 TRUNCATE 命令(来自官方文档:不幸的是,我们在 SQLite 中没有 TRUNCATE TABLE 命令,但您可以使用 SQLite DELETE 命令从现有表。)
  • 太糟糕了。但是,根据stackoverflow.com/questions/10854906/…,您可以通过在事务中运行删除命令并提交该事务来解决此问题。

标签: c# database entity-framework sqlite


【解决方案1】:

EF 数据库上下文维护它从内存中的数据库检索到的对象列表,直到它被销毁或卸载。

using (var ctx = new MyDbContext())
{
    var person1 = new Person { Id = 1 };
    ctx.Persons.Add(person1);
    await ctx.SaveChangesAsync();

    await context.Database.ExecuteSqlCommandAsync(string.Format("DELETE FROM `PersonModels`"));

    // This is the secret
    ((IObjectContextAdapter)ctx).ObjectContext.Detach(person1);

    ctx.Persons.Add(person1)
    await ctx.SaveChangesAsync();

}

【讨论】:

  • 谢谢,但我使用的是单独的上下文(在清除 Persons 表后,我处理上下文并创建一个新的上下文实例以添加条目)。另外,我的 ((IObjectContextAdapter)ctx).ObjectContext 不包含“Persons”(我的 DbContext 实现中只有 Persons 属性 -> DbSet&lt;PersonModel&gt; Persons,但 DbSet 没有 Detach()。)
  • 在您描述的情况下,我绝对无法重现该问题。我还更新了Detach 代码示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-21
  • 1970-01-01
  • 1970-01-01
  • 2014-07-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多