Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Entity framework 回滚事务抛出";已存在与此命令关联的打开的DataReader…“;错误_Entity Framework_.net Core_Entity Framework Core - Fatal编程技术网

Entity framework 回滚事务抛出";已存在与此命令关联的打开的DataReader…“;错误

Entity framework 回滚事务抛出";已存在与此命令关联的打开的DataReader…“;错误,entity-framework,.net-core,entity-framework-core,Entity Framework,.net Core,Entity Framework Core,我正在.NETCore2.0上使用实体框架Core2.0。为了重现这个问题,我制作了一个简单的控制台应用程序 //Program.cs 静态void Main(字符串[]参数) { 使用(var dbContext=new MyDbContext()) { 使用(var transaction=dbContext.Database.BeginTransaction()) { 尝试 { var blogs=dbContext.blogs .ToList();//由于我的博客类中的架构不匹配而引发错

我正在.NETCore2.0上使用实体框架Core2.0。为了重现这个问题,我制作了一个简单的控制台应用程序

//Program.cs
静态void Main(字符串[]参数)
{
使用(var dbContext=new MyDbContext())
{
使用(var transaction=dbContext.Database.BeginTransaction())
{
尝试
{
var blogs=dbContext.blogs
.ToList();//由于我的博客类中的架构不匹配而引发错误
//可能会或可能不会对数据库进行更改的其他内容
dbContext.SaveChanges();
Commit();
}
捕获(例外情况除外)
{
transaction.Rollback();//引发隐藏初始错误的第二个错误:“已经有一个打开的DataReader…”
}
}
}
}
我在将Blog类映射到数据库架构时故意犯了一个错误,因此当我在
dbContext.Blogs
实体框架上执行
.ToList()
时,会抛出一个无效的操作错误,类似于
读取Blog.Name的数据库值时发生异常,因为
Name
在数据库中是
nvarchar(max)
,但在我的
Blog
类中是
int

因此,现在我的
catch
语句尝试在事务期间发生任何错误时回滚事务,但该回滚会导致另一个错误,即最终记录的错误,从而隐藏初始错误

System.InvalidOperationException occurred
HResult=0x80131509
Message=There is already an open DataReader associated with this Command which must be closed first.
Source=<Cannot evaluate the exception source>
StackTrace:
at System.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommand command)
at System.Data.SqlClient.SqlInternalTransaction.Rollback()
at System.Data.SqlClient.SqlTransaction.Rollback()
at Microsoft.EntityFrameworkCore.Storage.RelationalTransaction.Rollback()
at ConsoleApp.Program.Main(String[] args) in C:\Users\mitch\OneDrive\Dev\EFCore\ConsoleApp\ConsoleApp\Program.cs:line 28
发生System.InvalidOperationException

HResult=0x80131509
Message=已经有一个与此命令关联的打开的DataReader,必须先关闭它。
来源=
堆栈跟踪:
位于System.Data.SqlClient.SqlInternalConnectionDS.ValidateConnectionForExecute(SqlCommand)
位于System.Data.SqlClient.SqlInternalTransaction.Rollback()处
在System.Data.SqlClient.SqlTransaction.Rollback()处
在Microsoft.EntityFrameworkCore.Storage.RelationalTransaction.Rollback()中
在C:\Users\mitch\OneDrive\Dev\EFCore\ConsoleApp\ConsoleApp\Program.cs中的ConsoleApp.Program.Main(字符串[]args)处:第28行
现在这是一个非常简单的例子,我意识到这里没有什么可承诺的。事实上,我正在运行一个ASP.NET核心应用程序,其中有一个全局事务包装器,因此一些请求可能只是读取,而其他请求可能是读取和更新

我做错什么了吗?据我所知,这是相当标准的,但我已经在谷歌上搜索了两天,没有发现任何人有同样的问题

当EF在为博客查询数据库时打开Data Reader,然后在执行查询中间出现异常,DATaReader将保持打开状态,因此在对该连接进行任何操作之后,我将得到打开的DATALAADER错误。如果是这样,我应该如何处理查询过程中发生的错误?我需要确保可能发生的任何更新都被回滚,并且我需要处理事务和连接。

这是System.Data.SqlClient.SqlTransaction中的一个错误,它也会在.NET Framework上重新启动。这也是EF核心中的一个bug,因为它不会在EF6上重新编程。我不确定这是否是一个已知的bug,对于efcore和SqlTransaction,可能会进行不同的分类。最终,Using块将回滚事务

下面是一个最小的ADO.NET复制程序:

using System;
using System.Data.SqlClient;

namespace ConsoleApp8
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var con = new SqlConnection("Server=localhost;database=tempdb;Integrated Security=true;MultipleActiveResultsets=false"))
            {
                con.Open();
                using (var tran = con.BeginTransaction())
                {
                    var cmd = new SqlCommand("select * from sys.objects", con, tran);
                    var rdr = cmd.ExecuteReader();
                    rdr.Read();

                    tran.Rollback();
                }
            }
        }
    }
}
和最低限度的EF核心复制:

using Microsoft.EntityFrameworkCore;
using System;
using System.Data.SqlClient;
using System.Linq;

namespace ConsoleApp8
{

    public class Foo
    {
        public int Id { get; set; }
    }
    public class Db : DbContext
    {
        public DbSet<Foo> Foos { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("Server=localhost;database=EfCoreTest;Integrated Security=true;MultipleActiveResultsets=false");
            base.OnConfiguring(optionsBuilder);
        }

    }
    class Program
    {
        static void Main(string[] args)
        {
            using (var db = new Db())
            {
                db.Database.EnsureDeleted();
                db.Database.EnsureCreated();
                db.Foos.Add(new Foo());
                db.SaveChanges();
            }

            using (var db = new Db())
            { 
                var tran = db.Database.BeginTransaction();
                foreach (var foo in db.Foos)
                {
                    tran.Rollback();
                }

            }

        }
    }
}

我打开了一期GitHub来跟踪这一问题:

感谢上帝,有人了解这个问题。我感谢您的详细回复,并感谢您在github上发表文章。我们将考虑使用MARS来解决这个问题,只需要确保没有任何明显的缺陷。它阻止了回滚。这已在2.1版本中修复。@Smit是的,我也在关注github问题。谢谢你的回复。不幸的是,还不知道下一个版本何时发布。
db.Database.ExecuteSqlCommand("if @@trancount > 0 rollback;");