实体框架 6 和 SQLite - 无法创建条目 PK 之前删除的条目

Posted

技术标签:

【中文标题】实体框架 6 和 SQLite - 无法创建条目 PK 之前删除的条目【英文标题】:Entity Framework 6 and SQLite - cannot create entry with PK of entry deleted before 【发布时间】: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 命令从现有表。) 太糟糕了。但是,根据***.com/questions/10854906/…,您可以通过在事务中运行删除命令并提交该事务来解决此问题。 【参考方案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 代码示例。

以上是关于实体框架 6 和 SQLite - 无法创建条目 PK 之前删除的条目的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Visual Studio 2013 中为 sqlite 配置实体框架 6

实体框架 6 不在 SQLite 数据库中创建表

无法读取 sqlite 数据库,使用 Visual Studio 2013 中的实体框架

无法将 MySQL 连接用于实体框架 6

实体框架 4.1 创建重复的查找条目

同时将实体框架与 SQL Server 和 SQLite 数据库一起使用