Ядро Entity Framework: друга операція, розпочата в цьому контексті до завершення попередньої операції


89

Я працюю над проектом 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, але ця робота не використовує ту саму сутність. Це все, що я можу вважати актуальним. Будь-які ідеї того, що може спричинити це?


1
Перевірте це .
Беркай

2
@Berkay Я бачив це та багато інших подібних питань і пробував їх. Мій метод був асинхронним, і я зробив його синхронізацією, щоб уникнути цих проблем. Я також намагаюся видалити відображення, також намагався видалити .ToPagedList, він продовжує видавати помилку.
Андре Луїз,

Було б непогано побачити повний слід стека
Evk

І знати, чи активовано кілька активних результатів
Джей

Зіткнувшись із тією ж проблемою, я виявив, що в моїй таблиці бази даних є цілі числа, що допускають обнулення. як тільки я встановив властивості своєї моделі сутності на відповідність обнулюваним int, це все почало працювати так, повідомлення для мене вводили в оману ...!
Завжди Навчання

Відповіді:


87

Я не впевнений, що ви використовуєте IoC та індекцію залежності для вирішення вашого DbContext там, де він може використовуватися. Якщо ви використовуєте і використовуєте власний IoC із .NET Core (або будь-якого іншого IoC-контейнера), і ви отримуєте цю помилку, обов’язково зареєструйте свій DbContext як перехідний. Роби

services.AddTransient<MyContext>();

АБО

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

замість

services.AddDbContext<MyContext>();

AddDbContext додає контекст як область дії, що може спричинити проблеми при роботі з кількома потоками.

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

Додавання його як перехідного також має свої мінуси. Ви не зможете вносити зміни до якоїсь сутності в декількох класах, які використовують контекст, оскільки кожен клас отримає власний екземпляр вашого DbContext.

Просте пояснення цього полягає в тому, що DbContextреалізація не є безпечною для потоків. Детальніше про це ви можете прочитати тут


2
Коли я використовую перехідні процеси, я отримую наступні помилки підключення (закриті чи утилізовані) 'OmniService.DataAccess.Models.OmniServiceDbContext'. System.ObjectDisposedException: Не вдається отримати доступ до віддаленого об'єкта. Поширеною причиною цієї помилки є усунення контексту, який було вирішено введенням залежностей, а потім спроба використовувати той самий екземпляр контексту в іншому місці програми. Це може статися, якщо ви викликаєте Dispose () у контексті або обгортаєте контекст у оператор using. ... Назва об'єкта: 'AsyncDisposer'.
Девід,

3
Привіт @David! Думаю, ви використовуєте, Task.Run(async () => context.Set...)не чекаючи цього, або не створюєте контекст db з обсягом, не чекаючи результату. Це означає, що ваш контекст, мабуть, уже утилізований при доступі до нього. Якщо ви використовуєте Microsoft DI, ви повинні створити область залежностей самостійно в межах цього Task.Run. Перевірте також ці посилання. stackoverflow.com/questions/45047877 / ... docs.microsoft.com/en-us/dotnet/api / ...
alsami

3
Як зазначалося раніше, якщо ви пропустите виклик асинхронного методу з ключовим словом await, ви зіткнетеся з цією проблемою.
Йеннефер

1
Це може бути добре, але потрібно бути більш продуманим щодо бажаного терміну служби та роздільної здатності доступу до даних, ніж кавалерно використовувати перехідний режим, не враховуючи обставин. Насправді, я вважаю рідкістю, коли хтось хоче, щоб контекст даних був тимчасовим. Якщо обсяг одиниці роботи - це щось, що включає більше ніж одну операцію з даними, обсяг транзакції повинен охоплювати більше, ніж це. Роздільність вашого контексту даних повинна відображати обсяг вашої одиниці роботи. Це те, що слід продумати, і це не універсальна відповідь.
Dave

3
@alsami ти мій герой. 6 годин болісної налагодження. Це було рішення. Якщо хтось ін’єктує IHttpContextAccessor у DbContext і Претензії не мають значення, це рішення. Щиро дякую, чоловіче.
jcmontx

56

У деяких випадках ця помилка виникає під час виклику асинхронного методу без awaitключового слова, що може бути просто вирішено додаванням awaitперед викликом методу. проте відповідь може бути не пов'язана із згаданим питанням, але вона може допомогти у вирішенні подібної помилки.


4
Це сталося зі мною. Зміна First()на await / FirstAsync()спрацьований.
Guilherme

Проголосувати. Також див. Jimlynn.wordpress.com/2017/11/16/… Джим Лінн "ПОМИЛКА РАМКИ ОРГАНІЗАЦІЇ : ДРУГА ОПЕРАЦІЯ, ЩО РОЗПОЧАЛАСЯ В ЦЬОМУ КОНТЕКСТІ ДО ЗАВЕРШЕННЯ ПОПЕРЕДНЬОЇ ОПЕРАЦІЇ. БУДЬ-ЯКИХ ЧЛЕНІВ ВІД КОНСТРУКЦІЇ НЕ ГАРАНТУЮТЬ БЕЗПЕЧНО.
granadaCoder

Дякую за це! Це була саме моя проблема ... Забув додати await для асинхронного методу mdethod.
AxleWack

Це сталося і зі мною, і цей коментар допоміг, коли я шукав, де я забув про зниклих. Як тільки я знайшов, проблема вирішена.
Сіон Хай,

42

Виняток означає, _contextщо використовується одночасно двома потоками; або два потоки в одному запиті, або два запити.

_contextМожливо, ваш оголошений статичний? Не повинно бути.

Або ви телефонуєте GetClientsкілька разів в одному і тому ж запиті з іншого місця у вашому коді?

Можливо, ви вже робите це, але в ідеалі ви б використовували ін'єкцію залежностей для свого DbContext, що означає, що ви будете використовувати AddDbContext()у вашому Startup.cs, і ваш конструктор контролера буде виглядати приблизно так:

private readonly MyDbContext _context; //not static

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

Якщо ваш код не такий, покажіть нам, і, можливо, ми можемо допомогти далі.


1
Можливо, це моя робота. Мені вдалося вирішити, подивіться мою відповідь. Але я позначаю вашу як правильну
Андре Луїз

Мій код точно такий, і ми часто відстежуємо "Другу операцію, розпочату в цьому контексті до завершення попередньої асинхронної операції. Використовуйте 'await', щоб переконатися, що будь-які асинхронні операції завершились до виклику іншого методу в цьому контексті. Будь-які члени екземпляра не є гарантовано безпечно для потоку. - на System.Data.Entity.Internal.ThrowingMonitor.EnsureNotEntered () ".
NMathur

@NMathur Чи використовуєте ви свій _contextоб'єкт в інших потоках ? Як всередині Task.Run()наприклад?
Габріель Лучі

@GabrielLuci всі мої методи є асинхронними, як показано нижче, чи це спричинить проблему. Моїх знань щодо цієї теми дуже мало. Чи можете ви підказати, де і що слід детально прочитати, щоб зрозуміти цю поведінку? загальнодоступна асинхронна задача <List <Item>> GetItems (int orderId) {List <Item> items = await _context.Item.Where (x => x.OrderId == orderId) .ToListAsync (); повернути предмети; }
NMathur

@NMathur Це виглядає добре. Просто переконайтеся, що ви завжди використовуєте awaitасинхронні методи. Якщо ви не використовуєте await, ви можете ненавмисно перейти до багатопоточності.
Габріель Лучі

8
  • Вирішіть мою проблему, використовуючи цей рядок коду у моєму файлі Startup.cs.
    Додавання перехідної служби означає, що кожного разу, коли служба запитується, створюється новий екземпляр, коли ви працюєте з введенням залежностей

           services.AddDbContext<Context>(options =>
                            options.UseSqlServer(_configuration.GetConnectionString("ContextConn")),
                 ServiceLifetime.Transient);
    

6

У мене була та сама проблема, і виявилося, що батьківська служба була сінглтоном. Тож контекст автоматично також став синглтонним. Незважаючи на те, що в DI було оголошено як "Час життя".

Впорскування служби з різним часом життя в іншу

  1. Ніколи не впорскуйте послуги Обсягу та перехідні процеси в службу Singleton. (Це фактично перетворює перехідну або сферичну послугу в одиночну.)

  2. Ніколи не впорскуйте перехідні служби в сферу дії (це перетворює перехідну послугу в область дії).


це було саме моє питання
Джонсополіс,

Це теж була моя проблема. Я реєстрував клас обробника як синглтон, а DbContext як перехідний. Мені довелося використовувати ServiceProvider в класі Handler, щоб отримати перехідний екземпляр з контейнера DI щоразу, коли обробник
потрапляє

5

У мене була та ж помилка. Це сталося тому, що я назвав метод, який був побудований public async void ...замість public async Task ....


4

Я думаю, що ця відповідь все одно може допомогти комусь і заощадити багато разів. Я вирішив подібну проблему, змінивши IQueryableна List(або на масив, колекцію ...).

Наприклад:

var list=_context.table1.where(...);

до

var list=_context.table1.where(...).ToList(); //or ToArray()...

2
ІМХО, Ця відповідь не заслуговує на мінус бали, вона просто погано виражена. .ToList () справді вирішує більшість проблем "другою операцією ..." завдяки тому, що він змушує негайно оцінювати вираз. Таким чином, немає жодних контекстних операцій.
vassilag

Це було питання в моєму випадку. У мене було xxx.Contens (z.prop) у реченні where запиту. xxx мав бути окремим масивом int [], вирішеним із попереднього запиту. На жаль, на той час, коли вдався другий запит, xxx все ще був IQueryable. Додавання xxx.ToArray () перед другим запитом виправило мою проблему.
Джейсон Бутера,

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();

Хіба контекст не буде виставлений лише після того, як все в використовуваному блоці завершить виконання?
Sello Mkantjwa

Коли дія розпоряджається, все розташовується в тому обсязі. Якщо у вас є завдання, яке виконується у фоновому режимі, і воно довше, ніж дія, у вас виникне ця проблема, якщо ви не створите новий обсяг для завдання, як це було зроблено у прикладі. З іншого боку, якщо ваше завдання може зайняти багато часу або ви хочете бути впевненими на 100%, що воно буде виконане, можливо, вам доведеться використовувати чергу. Якщо ви використовуєте Azure, ви можете використовувати черги шини обслуговування.
Франсіско

2

Entity Framework Core не підтримує кілька паралельних операцій, що виконуються в одному DbContextекземплярі. Це включає як паралельне виконання asyncзапитів, так і будь-яке явне одночасне використання з декількох потоків. Тому завжди await asyncдзвоніть негайно або використовуйте окремі DbContextекземпляри для операцій, які виконуються паралельно.


1

Моя ситуація інша: я намагався створити базу даних із 30 користувачами, які належать до певних ролей, тому я запускав цей код:

for (var i = 1; i <= 30; i++)
{
    CreateUserWithRole("Analyst", $"analyst{i}", UserManager);
}

Це була функція синхронізації. Всередині мене було 3 дзвінки:

UserManager.FindByNameAsync(username).Result
UserManager.CreateAsync(user, pass).Result
UserManager.AddToRoleAsync(user, roleName).Result

Коли я замінив .Resultна .GetAwaiter().GetResult(), ця помилка зникла.


0

Я отримав те саме повідомлення. Але в моєму випадку це не має сенсу. Моя проблема полягає в тому, що я помилково використав властивість "NotMapped". Можливо, це лише означає помилку синтаксису Linq або класу моделі в деяких випадках. Повідомлення про помилку видається оманливим. Початкове значення цього повідомлення полягає в тому, що ви не можете викликати асинхронізацію на одному і тому ж 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-operation-completed


0

У мене є фонова служба, яка виконує дію для кожного запису в таблиці. Проблема полягає в тому, що якщо я повторюю і модифікую деякі дані в одному екземплярі DbContext, ця помилка виникає.

Одним із рішень, як згадується в цій темі, є зміна часу життя DbContext на перехідний, визначаючи його як

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

але оскільки я роблю зміни в декількох різних службах і здійснюю їх відразу, використовуючи SaveChanges()метод, це рішення не працює в моєму випадку.

Оскільки мій код працює в службі, я робив щось на зразок

using (var scope = Services.CreateScope())
{
   var entities = scope.ServiceProvider.GetRequiredService<IReadService>().GetEntities();
   var writeService = scope.ServiceProvider.GetRequiredService<IWriteService>();
   foreach (Entity entity in entities)
   {
       writeService.DoSomething(entity);
   } 
}

мати можливість користуватися послугою, як якщо б це був простий запит. Отже, щоб вирішити проблему, я просто розділив одну область на дві, одну для запиту, а іншу для операцій запису приблизно так:

using (var readScope = Services.CreateScope())
using (var writeScope = Services.CreateScope())
{
   var entities = readScope.ServiceProvider.GetRequiredService<IReadService>().GetEntities();
   var writeService = writeScope.ServiceProvider.GetRequiredService<IWriteService>();
   foreach (Entity entity in entities)
   {
       writeService.DoSomething(entity);
   } 
}

Подібно до цього, ефективно використовуються два різні екземпляри DbContext.

Іншим можливим рішенням було б переконатися, що операція зчитування закінчилася перед початком ітерації. Це не дуже практично в моєму випадку, оскільки могло б бути багато результатів, які потрібно було б завантажити в пам’ять для операції, якої я намагався уникнути, використовуючи Queryable в першу чергу.


0

Мені вдалося отримати цю помилку, передавши метод IQueryableу метод, який потім використовував цей "список" IQueryable як частину іншого запиту до того самого контексту.

public void FirstMethod()
{
    // This is returning an IQueryable
    var stockItems = _dbContext.StockItems
        .Where(st => st.IsSomething);

    SecondMethod(stockItems);
}

public void SecondMethod(IEnumerable<Stock> stockItems)
{
    var grnTrans = _dbContext.InvoiceLines
        .Where(il => stockItems.Contains(il.StockItem))
        .ToList();
}

Для того, щоб зупинити це відбувається я використовував підхід тут і матеріалізовані цей список , перш ніж передати його другий метод, змінюючи виклик SecondMethodбудеSecondMethod(stockItems.ToList()


Це вирішило проблему, але чи це не уповільнить продуктивність. Чи існує якесь альтернативне рішення?
Dheeraj Kumar

0

По-перше, підтримайте (принаймні) відповідь Alsami. Це вивело мене на правильний шлях.

Але для тих, хто робить IoC, ось трохи глибше занурення.

Моя помилка (така ж, як інші)

Сталася одна або кілька помилок. (Друга операція, розпочата в цьому контексті до завершення попередньої операції. Це, як правило, спричинено різними потоками, що використовують один і той же екземпляр DbContext. Докладніше про те, як уникнути проблем із потоками з DbContext, див. На https://go.microsoft.com / fwlink /? linkid = 2097913. )

Налаштування мого коду. "Просто основи" ...

public class MyCoolDbContext: DbContext{
    public DbSet <MySpecialObject> MySpecialObjects {        get;        set;    }
}

і

public interface IMySpecialObjectDomainData{}

та (примітка, вводиться MyCoolDbContext)

public class MySpecialObjectEntityFrameworkDomainDataLayer: IMySpecialObjectDomainData{
    public MySpecialObjectEntityFrameworkDomainDataLayer(MyCoolDbContext context) {
        /* HERE IS WHERE TO SET THE BREAK POINT, HOW MANY TIMES IS THIS RUNNING??? */
        this.entityDbContext = context ?? throw new ArgumentNullException("MyCoolDbContext is null", (Exception)null);
    }
}

і

public interface IMySpecialObjectManager{}

і

public class MySpecialObjectManager: IMySpecialObjectManager
{
    public const string ErrorMessageIMySpecialObjectDomainDataIsNull = "IMySpecialObjectDomainData is null";
    private readonly IMySpecialObjectDomainData mySpecialObjectDomainData;

    public MySpecialObjectManager(IMySpecialObjectDomainData mySpecialObjectDomainData) {
        this.mySpecialObjectDomainData = mySpecialObjectDomainData ?? throw new ArgumentNullException(ErrorMessageIMySpecialObjectDomainDataIsNull, (Exception)null);
    }
}

І нарешті, мій багатопотоковий клас, який викликається з консольної програми (програма інтерфейсу командного рядка)

    public interface IMySpecialObjectThatSpawnsThreads{}

і

public class MySpecialObjectThatSpawnsThreads: IMySpecialObjectThatSpawnsThreads
{
    public const string ErrorMessageIMySpecialObjectManagerIsNull = "IMySpecialObjectManager is null";

    private readonly IMySpecialObjectManager mySpecialObjectManager;

    public MySpecialObjectThatSpawnsThreads(IMySpecialObjectManager mySpecialObjectManager) {
        this.mySpecialObjectManager = mySpecialObjectManager ?? throw new ArgumentNullException(ErrorMessageIMySpecialObjectManagerIsNull, (Exception)null);
    }
}

і накопичення DI. (Знову ж таки, це для консольного додатка (інтерфейс командного рядка) ... який має незначну поведінку, ніж веб-додатки)

private static IServiceProvider BuildDi(IConfiguration configuration) {
    /* this is being called early inside my command line application ("console application") */

    string defaultConnectionStringValue = string.Empty; /* get this value from configuration */

    ////setup our DI
    IServiceCollection servColl = new ServiceCollection()
        ////.AddLogging(loggingBuilder => loggingBuilder.AddConsole())

        /* THE BELOW TWO ARE THE ONES THAT TRIPPED ME UP.  */
        .AddTransient<IMySpecialObjectDomainData, MySpecialObjectEntityFrameworkDomainDataLayer>()
    .AddTransient<IMySpecialObjectManager, MySpecialObjectManager>()

    /* so the "ServiceLifetime.Transient" below................is what you will find most commonly on the internet search results */
     # if (MY_ORACLE)
        .AddDbContext<ProvisioningDbContext>(options => options.UseOracle(defaultConnectionStringValue), ServiceLifetime.Transient);
     # endif

     # if (MY_SQL_SERVER)
        .AddDbContext<ProvisioningDbContext>(options => options.UseSqlServer(defaultConnectionStringValue), ServiceLifetime.Transient);
     # endif

    servColl.AddSingleton <IMySpecialObjectThatSpawnsThreads,        MySpecialObjectThatSpawnsThreads>();

    ServiceProvider servProv = servColl.BuildServiceProvider();

    return servProv;
}

Мене здивувало (перехід на) перехідний для

        .AddTransient<IMySpecialObjectDomainData, MySpecialObjectEntityFrameworkDomainDataLayer>()
    .AddTransient<IMySpecialObjectManager, MySpecialObjectManager>()

Зверніть увагу, я думаю, оскільки IMySpecialObjectManager вводився в "MySpecialObjectThatSpawnsThreads", ці ін'єктовані об'єкти повинні були бути Перехідними для завершення ланцюжка.

Справа в тому, що ....... потрібен був не лише (Мій) DbContext .Transient ..., а більший шматок діаграми DI.

Порада щодо налагодження:

Цей рядок:

this.entityDbContext = context ?? throw new ArgumentNullException("MyCoolDbContext is null", (Exception)null);

Помістіть там свою точку розриву налагоджувача. Якщо ваш MySpecialObjectThatSpawnsThreads створює N кількість потоків (скажімо, 10 потоків, наприклад) ...... і цей рядок потрапляє лише один раз ... це ваша проблема. Ваш DbContext перетинає потоки.

БОНУС:

Я б запропонував прочитати це нижче за адресою url / article (oldie but goodie) про відмінності web-apps та console-apps

https://mehdi.me/ambient-dbcontext-in-ef6/

Ось заголовок статті на випадок зміни посилання.

УПРАВЛІННЯ DBCONTEXT ПРАВИЛЬНИМ ШЛЯХОМ З РАМКОЮ ENTITY 6: ГЛИБИННИЙ КЕРІВНИК

Я вирішив цю проблему з WorkFlowCore https://github.com/danielgerlag/workflow-core

  <ItemGroup>
    <PackageReference Include="WorkflowCore" Version="3.1.5" />
  </ItemGroup>

зразок коду нижче .., щоб допомогти майбутнім пошуковцям Інтернету

 namespace MyCompany.Proofs.WorkFlowCoreProof.BusinessLayer.Workflows.MySpecialObjectInterview.Workflows
    {
        using System;
        using MyCompany.Proofs.WorkFlowCoreProof.BusinessLayer.Workflows.MySpecialObjectInterview.Constants;
        using MyCompany.Proofs.WorkFlowCoreProof.BusinessLayer.Workflows.MySpecialObjectInterview.Glue;
        using MyCompany.Proofs.WorkFlowCoreProof.BusinessLayer.Workflows.WorkflowSteps;

        using WorkflowCore.Interface;
        using WorkflowCore.Models;

        public class MySpecialObjectInterviewDefaultWorkflow : IWorkflow<MySpecialObjectInterviewPassThroughData>
        {
            public const string WorkFlowId = "MySpecialObjectInterviewWorkflowId";

            public const int WorkFlowVersion = 1;

            public string Id => WorkFlowId;

            public int Version => WorkFlowVersion;

            public void Build(IWorkflowBuilder<MySpecialObjectInterviewPassThroughData> builder)
            {
                builder
                             .StartWith(context =>
                    {
                        Console.WriteLine("Starting workflow...");
                        return ExecutionResult.Next();
                    })

                        /* bunch of other Steps here that were using IMySpecialObjectManager.. here is where my DbContext was getting cross-threaded */


                    .Then(lastContext =>
                    {
                        Console.WriteLine();

                        bool wroteConcreteMsg = false;
                        if (null != lastContext && null != lastContext.Workflow && null != lastContext.Workflow.Data)
                        {
                            MySpecialObjectInterviewPassThroughData castItem = lastContext.Workflow.Data as MySpecialObjectInterviewPassThroughData;
                            if (null != castItem)
                            {
                                Console.WriteLine("MySpecialObjectInterviewDefaultWorkflow complete :)  {0}   -> {1}", castItem.PropertyOne, castItem.PropertyTwo);
                                wroteConcreteMsg = true;
                            }
                        }

                        if (!wroteConcreteMsg)
                        {
                            Console.WriteLine("MySpecialObjectInterviewDefaultWorkflow complete (.Data did not cast)");
                        }

                        return ExecutionResult.Next();
                    }))

                    .OnError(WorkflowCore.Models.WorkflowErrorHandling.Retry, TimeSpan.FromSeconds(60));

            }
        }
    }

і

ICollection<string> workFlowGeneratedIds = new List<string>();
                for (int i = 0; i < 10; i++)
                {
                    MySpecialObjectInterviewPassThroughData currentMySpecialObjectInterviewPassThroughData = new MySpecialObjectInterviewPassThroughData();
                    currentMySpecialObjectInterviewPassThroughData.MySpecialObjectInterviewPassThroughDataSurrogateKey = i;

                    ////  private readonly IWorkflowHost workflowHost;
                    string wfid = await this.workflowHost.StartWorkflow(MySpecialObjectInterviewDefaultWorkflow.WorkFlowId, MySpecialObjectInterviewDefaultWorkflow.WorkFlowVersion, currentMySpecialObjectInterviewPassThroughData);
                    workFlowGeneratedIds.Add(wfid);
                }

0

У моєму випадку я використовую компонент шаблону в Blazor.

 <BTable ID="Table1" TotalRows="MyList.Count()">

Проблема полягає у виклику методу (Count) у заголовку компонента. Щоб вирішити проблему, я змінив її так:

int total = MyList.Count();

і пізніше:

<BTable ID="Table1" TotalRows="total">

0

Я знаю, що цю проблему задавали два роки тому, але я просто мала цю проблему, і виправлення, яке я використав, справді допомогло.

Якщо ви робите два запити з однаковим контекстом - можливо, вам доведеться видалити файл AsNoTracking. Якщо ви все-таки використовуєте, AsNoTrackingви створюєте новий зчитувач даних для кожного прочитаного. Два пристрої для зчитування даних не можуть читати однакові дані.


0

У моєму випадку я використовував замок, який не дозволяє використовувати await і не створює попередження компілятора, коли ви не чекаєте асинхронізації.

Проблема:

lock (someLockObject) {
    // do stuff
    context.SaveChangesAsync();
}

// some other code somewhere else doing await context.SaveChangesAsync() shortly after the lock gets the concurrency error

Виправлення: Зачекайте асинхронізацію всередині замка, зробивши його блокуванням за допомогою .Wait ()

lock (someLockObject) {
    // do stuff
    context.SaveChangesAsync().Wait();
}

0

Інший можливий випадок: якщо ви використовуєте пряме з'єднання, не забудьте закрити if. Мені потрібно було виконати довільний запит SQL і прочитати результат. Це було швидке виправлення, я не хотів визначати клас даних, не налаштовувати "звичайне" з'єднання SQL. Так просто я повторно використовував підключення до бази даних EFC як var connection = Context.Database.GetDbConnection() as SqlConnection. Обов’язково телефонуйте connection.Close()перед тим, як зателефонувати Context.SaveChanges().


-1

У мене виникла та сама проблема, коли я намагаюся використовувати FirstOrDefaultAsync() метод асинхронізації в коді нижче. І коли я виправив FirstOrDefault()- проблему вирішили!

_context.Issues.Add(issue);
        await _context.SaveChangesAsync();

        int userId = _context.Users
            .Where(u => u.UserName == Options.UserName)
            .FirstOrDefaultAsync()
            .Id;
...

1
Це взагалі не пов’язано з FirstOrDefault () або FirstOrDefaultAsync (). Йдеться про використання dbContext.
sajadre

-2

Якщо ваш метод повертає щось назад, ви можете вирішити цю помилку, .Resultзавершивши роботу, а .Wait()якщо вона нічого не поверне.


-6

Мені просто вдалося змусити це знову працювати. Це не має великого сенсу, але це спрацювало:

  1. Видалити Hangfire із StartUp (я там створював свою роботу)
  2. Видалено базу даних Hangfire
  3. Перезапустив сервер

Я розслідую далі пізніше, але метод, який я викликав із hangfire, отримує DBContext, і це можлива причина.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.