为了账号安全,请及时绑定邮箱和手机立即绑定

如何使用 SQLite 删除整个数据库并使用 EF Core 重置更改跟踪器

如何使用 SQLite 删除整个数据库并使用 EF Core 重置更改跟踪器

Go
收到一只叮咚 2022-11-21 20:15:50
我有一个服务器客户端架构,其中服务器为客户端提供 Rest API 以同步整个数据库数据。他们将其保存到本地 SQLite 数据库中。该模型位于共享项目中,有时会发生变化。因此,客户端需要更新他们本地的 SQLite 数据库模式。这当然只发生在更新客户端软件之后(数据库文件保持不变)。它通常通过删除数据库文件并在之后重新创建来简单地实现。_context.Database.EnsureDeleted();_context.Database.EnsureCreated();AttachNewDataFromServerToDatabaseContext(_context);_context.SaveChanges();Rest API 服务被实例化为 singelton,并始终使用相同的数据库上下文对象。第一次同步工作正常。但是接下来的失败了:System.InvalidOperationException: The instance of entity type '***' cannot be tracked because another instance with the key value '{id:  ***}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.因此,尽管整个数据库已被删除,但更改跟踪器仍然知道“旧”实体。我对此的看法:每次同步数据库时实例化一个新的数据上下文可以修复它,因为更改跟踪器从“零”开始。在我看来这不是一个好的解决方案。如果 EnsureDeleted 也“重置”更改跟踪器或者您可以手动执行,那就太好了。你怎么看待这件事?谢谢你的帮助!
查看完整描述

2 回答

?
慕的地10843

TA贡献1785条经验 获得超8个赞

  • 每次同步数据库时实例化一个新的数据上下文可以修复它,因为更改跟踪器从“零”开始。在我看来这不是一个好的解决方案。

我宁愿说这是“正确”的解决方案。默认情况下,上下文元数据(又名Model)按上下文类型缓存,数据库连接由连接池维护,并且仅在需要时才打开/关闭。所以重用上下文实例的唯一好处是避免创建多个DbSet实例。

同时,跟踪器会保留大量“实体”实例,并防止它们在SaveChanges调用后被垃圾回收,而无需任何需要。不算潜在的多线程访问问题。

所以恕我直言,这就是要走的路——实例化新的上下文,用它做一些事情并处理它。

  • 如果 EnsureDeleted 也“重置”更改跟踪器或者您可以手动执行,那就太好了。

确实那会很棒。但目前EnsureDeletedEF Core 和 EF Core 都没有提供手动执行此操作的公共方式。

虽然有一种内部方法,但通常存在在未来某个 EF Core 版本中可能会更改的风险。添加

using Microsoft.EntityFrameworkCore.Infrastructure;

会允许你使用这样的东西

_context.ChangeTracker.GetInfrastructure().ResetState();

大概之前_context.Database.EnsureDeleted();。这基本上证明你真的应该使用第一个选项(新上下文)。

更新(EF Core 3.0): ChangeTracker甚至在内部也不再公开StateManager,所以我们需要

using Microsoft.EntityFrameworkCore.Internal;

分别

_context.GetDependencies().StateManager.ResetState();

更新(EF Core 5.0):感谢评论中的Vaclav Elias,现在 ChangeTracker 公开了一个 Clear() 方法来清除所有被跟踪实体的 DbContext。

_context.ChangeTracker.Clear();


查看完整回答
反对 回复 2022-11-21
?
浮云间

TA贡献1829条经验 获得超4个赞

以下几行对我有用。参考:https ://github.com/dotnet/efcore/issues/6282


    context.ChangeTracker

        .Entries()

        .ToList()

        .ForEach(e => e.State = EntityState.Detached);


    context.Database.EnsureDeleted();

    context.Database.EnsureCreated();


查看完整回答
反对 回复 2022-11-21
  • 2 回答
  • 0 关注
  • 71 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信