如何在不释放上下文的情况下刷新Entity Framework连接

8

在我们的应用程序中使用Entity Framework几年后,公司开始为用户部署笔记本电脑。这些笔记本电脑是在现场使用的,直接通过有线连接到我们的网络。

自那时以来,我们发现程序崩溃率大幅增加,异常日志显示:

System.Data.SqlClient.SqlException: A transport-level error has occurred when receiving results from the server. 
(provider: Session Provider, error: 19 - Physical connection is not usable)

我的理论是,问题源于笔记本电脑与个人电脑不同之处在于其会进入睡眠状态。我认为,当笔记本电脑进入睡眠状态时,网络适配器被禁用,而当它重新唤醒时,则被重新启用。我认为我们的程序仍然试图使用不存在的连接与服务器通信。

因此,我的想法是:

Microsoft.Win32.SystemEvents.PowerModeChanged

我可以检测到它的唤醒并刷新连接。问题是,我似乎唯一能做到这一点的方式是处理当前的 DbContext 并实例化一个新的。
这样做的问题是任何未提交的更改都将丢失。如果用户一整天都在更新记录,他们就会丢失工作。不仅如此,我们还必须遍历所有应用程序和视图模型,并纳入某种退出编辑模式的通知给用户。非常不美观。
我想到的第二个想法是创建一个克隆 DbContext 的方法。当计算机唤醒时,我可以创建一个新的 DbContext 并从旧的 DbContext 复制状态,然后释放旧的...但我们的一些数据模型非常庞大,为每个模型创建一个深度克隆方法将是相当艰巨的任务。
我认为这可能仍然是我们必须采取的方式...但如果有人知道在不丢失当前状态的情况下刷新 Entity Framework DbContext 连接的方式,我会很愚蠢不去尝试的。
我将感激任何人的建议。

3
不确定您的设计类型,但是在内存中保存大量未保存的信息并不是一个好主意。您应该以某种方式定期自动保存信息。至少这样,如果出现任何数据丢失,损失将被最小化。许多应用程序(包括Web应用程序)都使用此策略。 - King King
这是一个很好的观点。我们不自动保存的原因是因为我们允许用户决定是否保存更改或取消。为此,有两种策略:1)在编辑开始时在内存中创建原始数据的副本,随着数据的更改而维护对数据库的实时更新,在取消时使用旧副本更新数据。2)在内存中保留工作副本,并仅在用户选择保存更改时将其持久化到数据库中。从实现的角度来看,第二个选项更简单,也是我们使用的方法。尽管如此,它确实会导致像上面看到的问题。 - Chronicide
有没有在笔记本电脑进入睡眠状态之前发生的事件可用?您可以事先保存,关闭连接,当它唤醒时再次打开它。 - Matt
@Matt 是的,我可以使用我之前提到的相同事件处理程序来检测系统即将进入睡眠状态的时刻,但是无论我在睡眠前还是睡眠后检测到更改,我都面临着相同的问题。我不能只是保存数据,因为用户可能一直在修改数据,并期望能够撤销。关闭和打开Entity Framework连接实际上并不会刷新它。它仍然会尝试使用已过期的适配器进行打开。我所见过的唯一获取新连接的方法就是处置整个DbContext。DbContext.Database.Connection属性是只读的,所以我不能替换它。 - Chronicide
在这种情况下,我能想到的唯一方法是在唤醒之前序列化它,然后在唤醒后反序列化它,例如如果您创建一个FIFO队列(可以只是一个文件),以确保按正确顺序进行更新。 - Matt
2个回答

3

我不确定这是否对你的情况有帮助,但你可以检查你的DbConetxt类使用的连接状态,并可能重新打开它。

if(context.Database.Connection.State == ConnectionState.Closed) {
    context.Database.Connection.Open();
}

也可以在 DbContext 的构造函数中传递连接对象,并手动管理该连接。

var conn = new SqlConnection("{connectionString}"));
var context =  new DbContext(conn, contextOwnsConnection: false);

...

if(conn.State == ConnectionState.Closed) {
    conn.Open(); 
}
context.SaveChanges(); 

...

context.Dispose();
conn.Dispose();

如果您想在EF 5或更早版本中使用此代码,将存在一些限制。请参阅官方文档


0

我本来只是想发表评论,但是我没有足够的声望点数来这样做,所以无论如何,我想知道是否有可能使用Entity Framework在离线状态下工作?也许下面链接中的文章可以帮助你:

https://msdn.microsoft.com/en-us/data/jj592676.aspx


谢谢提供参考。不幸的是,它并没有解决Entity Framework尝试使用已断开连接通信的问题。话虽如此,这是一篇关于如何将实体附加到上下文的清晰文章,如果我必须创建一个克隆方法,这可能非常有帮助...而不是创建新条目,我可以附加标记为添加或修改的现有条目从我的旧上下文中。这需要一些实验,但仍然是一个非常好的资源。谢谢。 - Chronicide

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