it-roy-ru.com

Entity Framework Core: вторая операция началась в этом контексте до завершения предыдущей операции

Я работаю над проектом ASP.Net Core 2.0 с использованием Entity Framework Core 

<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.1" />
  <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.0"/>

И в одном из моих методов списка я получаю эту ошибку:

InvalidOperationException: A second operation started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.
Microsoft.EntityFrameworkCore.Internal.ConcurrencyDetector.EnterCriticalSection()

Это мой метод:

    [HttpGet("{currentPage}/{pageSize}/")]
    [HttpGet("{currentPage}/{pageSize}/{search}")]
    public ListResponseVM<ClientVM> GetClients([FromRoute] int currentPage, int pageSize, string search)
    {
        var resp = new ListResponseVM<ClientVM>();
        var items = _context.Clients
            .Include(i => i.Contacts)
            .Include(i => i.Addresses)
            .Include("ClientObjectives.Objective")
            .Include(i => i.Urls)
            .Include(i => i.Users)
            .Where(p => string.IsNullOrEmpty(search) || p.CompanyName.Contains(search))
            .OrderBy(p => p.CompanyName)
            .ToPagedList(pageSize, currentPage);

        resp.NumberOfPages = items.TotalPage;

        foreach (var item in items)
        {
            var client = _mapper.Map<ClientVM>(item);

            client.Addresses = new List<AddressVM>();
            foreach (var addr in item.Addresses)
            {
                var address = _mapper.Map<AddressVM>(addr);
                address.CountryCode = addr.CountryId;
                client.Addresses.Add(address);
            }

            client.Contacts = item.Contacts.Select(p => _mapper.Map<ContactVM>(p)).ToList();
            client.Urls = item.Urls.Select(p => _mapper.Map<ClientUrlVM>(p)).ToList();
            client.Objectives = item.Objectives.Select(p => _mapper.Map<ObjectiveVM>(p)).ToList();
            resp.Items.Add(client);
        }

        return resp;
    }

Я немного растерялся, особенно потому, что он работает, когда я запускаю его локально, но при развертывании на моем промежуточном сервере (IIS 8.5) он получает эту ошибку, и она работает нормально. Ошибка начала появляться после увеличения максимальной длины одной из моих моделей. Я также обновил максимальную длину соответствующей модели представления. И есть много других методов списка, которые очень похожи, и они работают.

У меня была запущена работа Hangfire, но эта работа не использует ту же сущность. Это все, что я считаю актуальным. Есть идеи, что может быть причиной этого?

14
André Luiz

Исключение означает, что _context используется двумя потоками одновременно; либо два потока в одном запросе, либо по двум запросам.

Возможно, ваш _context объявлен статическим? Так не должно быть.

Или вы вызываете GetClients несколько раз в одном и том же запросе из другого места в вашем коде?

Возможно, вы уже делаете это, но в идеале вы должны использовать внедрение зависимостей для своей DbContext, что означает, что вы будете использовать AddDbContext() в своем Startup.cs, и ваш конструктор контроллера будет выглядеть как-то как это:

private readonly MyDbContext _context; //not static

public MyController(MyDbContext context) {
    _context = context;
}

Если ваш код не такой, покажите нам, и, возможно, мы сможем помочь в дальнейшем.

15
Gabriel Luci

Я не уверен, что вы используете IoC и Dependency Injection для разрешения вашего DbContext, где бы он ни использовался. Если вы это делаете и используете собственный IoC из .NET Core (или любого другого IoC-контейнера) и получаете эту ошибку, обязательно зарегистрируйте ваш DbContext как временный. Делать

services.AddTransient<MyContext>();

OR

services.AddDbContext<MyContext>(ServiceLifetime.Transient);

вместо

services.AddDbContext<MyContext>();

AddDbContext добавляет контекст как область видимости, что может вызвать проблемы при работе с несколькими потоками. 

Также операции async/await могут вызывать такое поведение при использовании асинхронных лямбда-выражений.

Добавление его в качестве переходного также имеет свои недостатки. Вы не сможете вносить изменения в некоторые объекты в нескольких классах, использующих контекст, потому что каждый класс получит свой экземпляр вашего DbContext.

24
alsami

Эта ошибка в некоторых случаях вызвана этим сценарием: вы вызываете метод async , но не используете await перед вызовом метода. моя проблема решена добавлением await перед методом. однако ответ может не относиться к указанному вопросу, но может помочь в подобной ошибке.

4
Hamid Nasirloo

Я столкнулся с той же проблемой, но причина не была ни одна из перечисленных выше. Я создал задачу, создал область действия внутри задачи и попросил контейнер получить сервис. Это работало нормально, но затем я использовал второй сервис внутри задачи, и я забыл также попросить его в новой области. Из-за этого 2-й сервис использовал DbContext, который уже был удален.

                Task task = Task.Run(() =>
                {
                    using (var scope = serviceScopeFactory.CreateScope())
                    {
                        var otherOfferService = scope.ServiceProvider.GetService<IOfferService>();
                        // everything was ok here. then I did: 
                        productService.DoSomething(); // (from the main scope) and this failed because the db context associated to that service was already disposed.
                        ...

                    }
                }

Я должен был сделать это:

var otherProductService = scope.ServiceProvider.GetService<IProductService>();
otherProductService.DoSomething();
1
Francisco Goldenstein

Я получил то же сообщение. Но это не имеет никакого смысла в моем случае. Моя проблема в том, что я использовал свойство NotMapped по ошибке. Возможно, в некоторых случаях это означает только ошибку синтаксиса Linq или класса модели. Сообщение об ошибке кажется вводящим в заблуждение. Первоначальное значение этого сообщения заключается в том, что вы не можете вызывать async для одного и того же dbcontext более одного раза в одном запросе.

[NotMapped]
public int PostId { get; set; }
public virtual Post Post { get; set; }

Вы можете проверить эту ссылку для подробностей, https://www.softwareblogs.com/Posts/Details/5/error-a-second-operation-started-on-this-context-before-a-previous -операция завершена

0
Sharon Zhou