代码之家  ›  专栏  ›  技术社区  ›  Neutrino

为什么循环中的实体框架核心调用抛出InvalidOperationException?

  •  1
  • Neutrino  · 技术社区  · 7 年前

    // Arrange.
    using(var context = new BasicContext())
    {
       Author[] authors = new[]
       {
          new Author { Name = "Bob"},
          new Author { Name = "Fred" }
       };
       context.Authors.AddRange(authors);
    
       Book[] books = new[]
       {
          new Book { Title = "Book 1" },
          new Book { Title = "Book 2" }
       };
    
       context.SaveChanges();            
    }
    
    // Act.
    bool exception = false;
    
    using(var context = new BasicContext())
    {
       foreach(Author a in context.Authors)
       {
          try
          {
             string title = context.Books.First().Title;
          }
          catch(Exception)
          {
             exception = true;
          }
       }
    }
    
    // Assert.
    Assert.False(exception);
    

    使用Postgress的实体连接器(Npgsql)引发的异常为:

    Npgsql.NpgsqlOperationInProgressException : A command is already in progress: SELECT "a"."AuthorId", "a"."Name"
    FROM "Authors" AS "a"
    Stack Trace:
       at Npgsql.NpgsqlConnector.StartUserAction(ConnectorState newState, NpgsqlCommand command)
       at Npgsql.NpgsqlCommand.<ExecuteDbDataReader>d__92.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
       at System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
       at Npgsql.NpgsqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
       at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, String execute
    Method, IReadOnlyDictionary`2 parameterValues, Boolean closeConnection)
       at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteReader(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
       at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable.Enumerator.BufferlessMoveNext(Boolean buffer)
       at Microsoft.EntityFrameworkCore.Query.QueryMethodProvider.<_ShapedQuery>d__3`1.MoveNext()
       at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
       at lambda_method(Closure , QueryContext )
       at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass20_0`1.<CompileQueryCore>b__0(QueryContext qc
    )
       at System.Linq.Queryable.First[TSource](IQueryable`1 source)
       at BasicTesting.BasicTests.TestEnumerate() in C:\_Home\Development\Workspaces\DotnetCoreTesting\EntityTesting3\BasicTesting\BasicTests.cs:line 147If 'foreach(Author a in context.Authors)' is replaced with 'foreach(Author a in context.Authors.ToArray())' no exception occurs.
    

    这不是我所期望的。

    当foreach循环到达上下文时。应评估作者。当子序列的书籍。“First”表达式导致另一个数据库操作—不应存在正在进行的现有操作。

    1 回复  |  直到 7 年前
        1
  •  1
  •   bricelam    7 年前

    一些提供商不支持多个开放读卡器。避免这种情况的最好方法是在查询书籍之前读完所有作者。正在添加 .ToList() 这是最简单(但不一定是最好)的方法。

    foreach (Author a in context.Authors.ToList())
    {
        // ... context.Books ...
    }