dotConnect с EntityFramework Ядро возвращает Коллекция была изменена; операция перечисления может не выполняться
У меня есть приложение, использующее ASP.Net Core RC2 и Entity Framework Core RC2 и использующее драйвер dotConnect для Oracle (dotConnect пока не поддерживает EF Core 1.0).
Я пытаюсь запустить 8 GET одновременно для разных записей, и я получаю эту ошибку:
Исключение типа "System.InvalidOperationException" произошло в Microsoft.EntityFrameworkCore.dll, но не было обработано в коде пользователя
Дополнительная информация: коллекция была изменена; Операция перечисления может не выполняться.
Исключение выдается из этой строки метода Get на контроллере:
return Ok(_context.Blogs.Include(blog => blog.Posts).FirstOrDefault(blog => blog.Id == id));
Я нашел много вопросов по этому вопросу, но обычно проблема заключается в том, что несколько потоков используют один и тот же экземпляр объекта или изменяют объект во время итерации, но, похоже, ни один из них не имеет здесь значения.
Я добавляю контекст БД в Startup.cs через внедрение зависимостей:
services.AddDbContext<BlogsModel.Model>();
Каждый вызов имеет свой собственный контроллер и экземпляр контекста, который я проверял, выводя оба хэша:
[HttpGet("{id}")]
public IActionResult Get(int id)
{
Console.WriteLine($"{GetHashCode()} - {_context.GetHashCode()}");
return Ok(_context.Blogs.Include(blog => blog.Posts).FirstOrDefault(blog => blog.Id == id));
}
Если я уберу часть "Включить" и получу только блог, она будет работать нормально.
[HttpGet("{id}")]
public IActionResult Get(int id)
{
Console.WriteLine($"{GetHashCode()} - {_context.GetHashCode()}");
return Ok(_context.Blogs.FirstOrDefault(blog => blog.Id == id));
}
Я также попробовал асинхронную версию, но я все еще получаю ошибку:
[HttpGet("{id}")]
public IActionResult Get(int id)
{
Console.WriteLine($"{GetHashCode()} - {_context.GetHashCode()}");
var task = _context.Blogs.Include(blog => blog.Posts).FirstOrDefaultAsync(blog => blog.Id == id);
task.Wait();
return Ok(task.Result);
}
Модель очень проста:
create table BLOGS
(
id NUMBER not null,
name VARCHAR2(200) not null
);
alter table BLOGS
add constraint PK_BLOGS primary key (ID);
create table POSTS
(
id NUMBER not null,
blog_id NUMBER not null,
title VARCHAR2(200) not null,
content VARCHAR2(500) not null
);
alter table POSTS
add constraint PK_POSTS primary key (ID);
alter table POSTS
add constraint FK_POSTS_BLOG foreign key (BLOG_ID)
references BLOGS (ID);
declare
blogId number := 0;
postId number := 0;
begin
for x in 1..1000 loop
blogId := blogId + 1;
insert into blogs values (blogId, 'Blog ' || blogId);
for x in 1..5 loop
postId := postId + 1;
insert into posts values (postId, blogId, 'Post ' || postId, 'Content for post ' || postId);
end loop;
end loop;
commit;
end;
/
Полный код для контроллера:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using BlogsModel;
using Microsoft.EntityFrameworkCore;
namespace BlogOracle.Controllers
{
[Route("api/[controller]")]
public class BlogsController : Controller
{
private Model _context;
public BlogsController(Model context)
{
_context = context;
}
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(int id)
{
Console.WriteLine($"{GetHashCode()} - {_context.GetHashCode()}");
return Ok(_context.Blogs.Include(blog => blog.Posts).FirstOrDefault(blog => blog.Id == id));
}
}
}
И стек вызовов:
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
at System.Linq.Enumerable.Any[TSource](IEnumerable`1 source)
at Microsoft.EntityFrameworkCore.Query.Expressions.SelectExpression.GetProjectionTypes()
at Microsoft.EntityFrameworkCore.Query.Sql.DefaultQuerySqlGenerator.CreateValueBufferFactory(IRelationalValueBufferFactoryFactory relationalValueBufferFactoryFactory, DbDataReader dataReader)
at Microsoft.EntityFrameworkCore.Internal.NonCapturingLazyInitializer.EnsureInitialized[TParam,TValue](TValue& target, TParam param, Func`2 valueFactory)
at Microsoft.EntityFrameworkCore.Query.Internal.ShaperCommandContext.NotifyReaderCreated(DbDataReader dataReader)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable.Enumerator.MoveNext()
at Microsoft.EntityFrameworkCore.Query.Internal.IncludeCollectionIterator.<GetRelatedValues>d__4.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.Include(QueryContext queryContext, Object entity, IReadOnlyList`1 navigationPath, IReadOnlyList`1 relatedEntitiesLoaders, Int32 currentNavigationIndex, Boolean queryStateManager)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.Include(QueryContext queryContext, Object entity, IReadOnlyList`1 navigationPath, IReadOnlyList`1 relatedEntitiesLoaders, Boolean queryStateManager)
at Microsoft.EntityFrameworkCore.Query.QueryMethodProvider.<_Include>d__30`1.MoveNext()
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
at lambda_method(Closure , QueryContext )
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass19_1`1.<CompileQuery>b__1(QueryContext qc)
at BlogOracle.Controllers.BlogsController.Get(Int32 id) in c:\Projetos\dotnet\BlogOracle\src\BlogOracle\Controllers\BlogsController.cs:line 26
at lambda_method(Closure , Object , Object[] )
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeActionAsync>d__6.MoveNext()
Полный код здесь: https://github.com/ricsmania/BlogsOracleEntityFramework
Я делаю что-то не так или это может быть ошибка с компонентом?