Entity Framework Core连接管理

6
在一个asp.net core项目中,我需要一个加密的SQLite数据库。为此,我创建了自己的SqliteEncryptedConnection,它继承自Microsoft.Data.Sqlite.SqliteConnection,并在Open()方法中设置加密密钥(执行PRAGMA key = ...)。
我有一个扩展方法来配置我的EF上下文,通过创建连接并将其传递给上下文。
    public static void UseEncryptedSqlite(this DbContextOptionsBuilder optionsBuilder, string connectionString, string password)
    {
        var connection = new SqliteEncryptedConnection(connectionString, password);
        connection.Open();
        optionsBuilder.UseSqlite(connection);
    }

在将连接交给EF之前,我必须先打开它,否则EF会为每个单独的查询自动开关连接,而且现在Open()方法的成本相当高。

我的问题是这样做后我的连接从未被释放或关闭!

  1. 在Open方法中设置加密密钥是否正确?
  2. 有没有办法知道上下文被释放了?或者在上下文被释放后配置它来关闭和释放连接?
  3. 是否有其他(更好)的管理连接的方法?

一个不太好的解决方法是在EF上下文的Dispose方法中释放连接,但我真的不想处理一个被注入并且不是上下文拥有的依赖项。


如果我正确理解了您的问题,那么这是设计上的。DbContextOptions对象不会被处理并且将被重用于所有EF Core DbContext实例,因为选项在DbContext初始化时传递给它。自2.0预览版1以来,甚至可以对DbContext实例进行轮询以获得高性能场景,请参阅此博客文章 - Tseng
@Tseng 连接没有被重复使用。每次注入新的DbContext时都会调用此方法。-> 每个Web请求1次。幸运的是,这些连接似乎被正确地垃圾回收了。因此,最后,我不知道在垃圾回收发生之前是否需要调用dispose/close。 - sroll
你找到解决方法了吗?我也遇到了同样的问题,EF Core上下文没有关闭连接。在我的情况下,我无法在选项对象中传递已关闭的连接,因为我需要在分片环境中使用连接,并且这是我从“ShardMap”对象的“OpenConnectionForKey”方法中接收它的方式。 - Adrian Pavel
@AdrianPavel 我回答了自己的问题,并得到了Brice Lambson的回复。对于您的情况,如果该连接仅被单个上下文使用,则可以在上下文“Dispose”方法中安全地处理它。 - sroll
1个回答

5

我收到了EF核心团队的Brice Lambson的回复:

你正在正确的方向上——尽量少打开连接。记住,SQLite连接本质上只是文件流,所以将它们保持打开时间更长并不是一个问题。

如果每个连接只有一个DbContext实例,即使它是外部创建的,DbContext仍然可以拥有该连接。只需在DbContext.Dispose()内部处理连接即可。

如果这还不够,您可以尝试创建一个连接池。管理其生命周期可能会变得棘手。重要的是,在创建它的线程之外不要使用连接。

使用Cache=Shared(即共享缓存模式)也可能有助于提高吞吐量。


我有一个类似的情况,通过添加密码保护的Sqlite连接,我注意到了严重的性能问题。你有同样的经历吗?如果是这样,你是如何解决的? - Shuaib

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接