سلام
این خطا یعنی اینکه DbContext شما در جای دیگر درگیر است.
این اتفاق در دوحالت رخ میدهد.
اول) برنامه های چند-ریسمانه که در یک زمان چند تکه از کد در حال اجرا است و در واقع درستش آن است که هر بخش و ریسمان DbContext مجزای خودش را داشته باشد.
دوم) برنامه شما به صورت تودرتو یا بیرون حلقه و داخل حلقه در حال استفاده از DbContext است ، که با توضیحات تان
مشکل شما از همین نوع است .
var iqueryable_data = dbContext1.Table.Where(...).GroupJoin(...).Take(...)...;
foreach (var row in iqueryable_data)
{
//... any code ...
dbContext1.SaveChanges(); //Error
}
در کد بالا روی یک شی IQueryable حلقه read اطلاعات ایجاد کرده ایم ولی در همان حلقه در حال write اطلاعات هستیم.
به صورت عادی شما نمیتوانید از یک DbContext در دو کار همزمان و قبل از پایان قبلی استفاده کنید.
سه راه حل ساده میتوان مطرح کرد:
راه حل اول) از دو عدد DbContext مجزا استفاده کنید
var iqueryable_data = dbContext1 .Table.Where(...).GroupJoin(...).Take(...)...;
foreach (var row in iqueryable_data)
{
//... any code ...
dbContext2 .SaveChanges(); //OK
}
راه حل دوم) عملیات read قبلی را با ToList پایان دهید.
var ilist_data = dbContext1.Table.Where(...).GroupJoin(...).Take(...)...ToList() ;
foreach (var row in ilist_data)
{
//... any code ...
dbContext1.SaveChanges(); //OK
}
فرمان ToList تمام اطلاعات را میخواند و کار خواندن اطلاعات را تمام میکند و DbContext برای اعمال بعدی آزاد میشود.
در واقع ToList یک foreach مجزا را اجرا میکند که اطلاعات را میخواند، شبیه این کد
شما نیاز به نوشتن این کد ندارید، این کد فقط برای فهم اتفاق صحیحی است که باید رخ دهد
var iqueryable_data = dbContext1.Table.Where(...).GroupJoin(...).Take(...)...;
//Start read from dbContext1
//ToList
var ilist_data = new List<...>();
foreach (var row in iqueryable_data)
ilist_data.Add(row);
//End read from dbContext1
//Start write from dbContext1
foreach (var row in ilist_data)
{
//... any code ...
dbContext1.SaveChanges();
}
//End write from dbContext1
راه حل سوم) چرا فقط یک خط دستور نهایی SaveChanges را به بیرون حلقه منتقل نمیکنید تا read تمام شده باشد.
بدین شکل، تمام تغییرات هم در یک واحد تراکنشی به دیتابیس ارسال شده و انجام میشود.
var iqueryable_data = dbContext1.Table.Where(...).GroupJoin(...).Take(...)...;
foreach (var row in iqueryable_data)
{
//... any code ...
}
dbContext1.SaveChanges(); //OK
موفق باشید.