gpt4 book ai didi

.NET Entity Framework 和事务

转载 作者:行者123 更新时间:2023-12-01 17:57:26 24 4
gpt4 key购买 nike

作为 Entity Framework 的新手,我真的很困惑如何继续处理这组问题。在我目前正在进行的项目中,整个站点都与 EF 模型高度集成。最初,对 EF 上下文的访问是使用依赖注入(inject) Bootstrap 进行控制的。由于操作原因,我们无法使用 DI 库。我删除了它并在需要时使用了上下文对象的各个实例的模型。我开始遇到以下异常:

The type 'XXX' has been mapped more than once.

我们得出的结论是,上下文的不同实例导致了此问题。然后,我将上下文对象抽象为每个线程/页面访问的单个静态实例。我现在遇到有关交易的几个异常之一:

New transaction is not allowed because there are other threads running in the session.

The transaction operation cannot be performed because there are pending requests working on this transaction.

ExecuteReader requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized.

最后一个异常发生在加载操作上。我并没有尝试将上下文状态保存回失败线程上的数据库。然而,还有另一个线程执行此类操作。

这些异常充其量只是间歇性的,但我已经设法使站点进入由于事务锁定而拒绝新连接的状态。不幸的是我找不到异常详细信息。

我想我的第一个问题是,是否应该从静态单实例中使用 EF 模型?另外,是否可以消除 EF 中事务的需要?我尝试使用 TransactionScope 对象但没有成功...

说实话,我被困在这里,无法理解为什么(应该是)相当简单的操作会导致这样的问题......

最佳答案

在 Web 应用程序中创建一个全局 Entity Framework DbContext 是非常糟糕的。 DbContext 类不是线程安全的( Entity Framework v1 的 ObjectContext 类也是如此)。它是围绕 unit of work 的概念构建的。这意味着您使用它来操作单个用例:因此用于业务交易。它旨在处理一个请求。

您遇到的异常是因为您为每个请求创建一个新事务,但尝试使用相同的DbContext。您很幸运,DbContext 检测到了这一点并抛出异常,因为现在您发现这不起作用。

DbContext 包含数据库中实体的本地缓存。它允许您进行大量更改并最终将这些更改提交到数据库。当使用单个静态 DbContext 时,多个用户在该对象上调用 SaveChanges,它应该如何知道哪些内容应该提交,哪些内容不应该提交?

因为它不知道,所以它会保存所有更改,但此时另一个请求可能仍在进行更改。如果幸运的话,EF 或您的数据库将会失败,因为实体处于无效状态。如果您运气不好,处于无效状态的实体会成功保存到数据库中,并且您可能会在几周后发现您的数据已损坏。

解决您的问题的方法是创建 at least one DbContext per request 。虽然理论上您可以在用户 session 中缓存对象上下文,但这也是一个坏主意,因为在这种情况下,DbContext 通常会存在太长的时间并且会包含过时的数据(因为它的内部缓存将不会自动刷新)。

另请注意,每个线程拥有一个 DbContext 与整个 Web 应用程序拥有一个实例一样糟糕。 ASP.NET 使用线程池,这意味着在 Web 应用程序的生命周期中将创建有限数量的线程。这基本上意味着在这种情况下,这些 DbContext 实例在应用程序的生命周期内仍然存在,从而导致与数据过时相同的问题。

您可能认为在单个 .NET(托管)线程的线程情况下存储 DbContext 是线程安全的,但通常情况并非如此,因为 ASP.NET一种异步模型,允许在与启动线程不同的线程上完成请求(最新版本的 MVC 和 Web API 甚至允许任意数量的线程按顺序处理一个请求)。这意味着启动请求并创建 DbContext 的线程可以在初始请求完成之前很久就可以处理另一个请求。然而,该请求中使用的对象(例如网页、 Controller 或任何业务类)可能仍然引用该DbContext。由于新的 Web 请求在同一线程中运行,因此它将获得与旧请求所使用的相同的 DbContext 实例。这会再次导致应用程序中出现竞争条件,并导致与一个全局 DbContext 实例导致的线程安全问题相同的问题。

关于.NET Entity Framework 和事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3266295/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com