Inti Kerangka Kerja Entitas: Operasi kedua dimulai pada konteks ini sebelum operasi sebelumnya selesai

98

Saya sedang mengerjakan proyek ASP.Net Core 2.0 menggunakan 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"/>

Dan di salah satu metode daftar saya, saya mendapatkan kesalahan ini:

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

Ini adalah metode saya:

    [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;
    }

Saya agak tersesat terutama karena itu berfungsi ketika saya menjalankannya secara lokal, tetapi ketika saya menyebarkan ke server pementasan saya (IIS 8.5) itu membuat saya kesalahan ini dan itu berfungsi normal. Kesalahan mulai muncul setelah saya menambah panjang maksimal salah satu model saya. Saya juga memperbarui panjang maksimal Model Tampilan yang sesuai. Dan ada banyak metode daftar lain yang sangat mirip dan berfungsi.

Saya memiliki pekerjaan Hangfire yang sedang berjalan, tetapi pekerjaan ini tidak menggunakan entitas yang sama. Hanya itu yang menurut saya relevan. Ada gagasan tentang apa yang bisa menyebabkan ini?

André Luiz
sumber
1
Periksa ini .
Berkay
2
@Berkay Saya melihat itu dan banyak pertanyaan serupa lainnya dan mencobanya. Metode saya asinkron dan saya membuatnya disinkronkan untuk menghindari masalah ini. Saya juga mencoba untuk menghapus pemetaan, juga mencoba untuk menghapus .ToPagedList yang terus memunculkan kesalahan.
André Luiz
Akan lebih baik untuk melihat jejak tumpukan penuh
Evk
Dan untuk mengetahui apakah beberapa hasil aktif diaktifkan
Jay
Memiliki masalah yang sama saya menemukan saya memiliki integer nullable dalam tabel database saya. segera setelah saya mengatur properti model entitas saya untuk mencocokkan int nullable, semuanya mulai bekerja jadi, pesannya menyesatkan bagi saya ...!
AlwaysLearning

Jawaban:

98

Saya tidak yakin apakah Anda menggunakan IoC dan Dependency Injection untuk menyelesaikan DbContext Anda di mana pun itu mungkin digunakan. Jika Anda melakukannya dan Anda menggunakan IoC asli dari .NET Core (atau IoC-Container lainnya) dan Anda mendapatkan kesalahan ini, pastikan untuk mendaftarkan DbContext Anda sebagai Transient. Melakukan

services.AddTransient<MyContext>();

ATAU

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

dari pada

services.AddDbContext<MyContext>();

AddDbContext menambahkan konteks sebagai cakupan, yang mungkin menyebabkan masalah saat bekerja dengan beberapa utas.

Juga operasi async / Tunggulah, dapat menyebabkan perilaku ini, ketika menggunakan ekspresi lambda async.

Menambahkannya sebagai sementara juga memiliki kelemahannya. Anda tidak akan dapat membuat perubahan pada beberapa entitas di beberapa kelas yang menggunakan konteks karena setiap kelas akan mendapatkan contoh DbContext Anda sendiri.

Penjelasan sederhananya adalah, bahwa DbContextpenerapannya tidak aman untuk thread. Anda dapat membaca lebih lanjut tentang ini di sini

alsami
sumber
2
Ketika saya menggunakan sementara saya mendapatkan kesalahan koneksi berikut (ditutup atau dibuang) 'OmniService.DataAccess.Models.OmniServiceDbContext'. System.ObjectDisposedException: Tidak dapat mengakses objek yang dibuang. Penyebab umum kesalahan ini adalah membuang konteks yang telah diselesaikan dari injeksi ketergantungan dan kemudian mencoba menggunakan contoh konteks yang sama di tempat lain dalam aplikasi Anda. Ini dapat terjadi jika Anda memanggil Dispose () pada konteks, atau membungkus konteks dalam pernyataan menggunakan. ... Nama objek: 'AsyncDisposer'.
David
5
Hai @Dvid! Saya kira Anda menggunakan Task.Run(async () => context.Set...)tanpa menunggu atau membuat konteks db terbatas tanpa menunggu hasilnya. Ini berarti konteks Anda mungkin sudah dibuang saat mengaksesnya. Jika Anda menggunakan Microsoft DI, Anda harus membuat sendiri cakupan ketergantungan di dalamnya Task.Run. Lihat tautan ini juga. stackoverflow.com/questions/45047877/… docs.microsoft.com/en-us/dotnet/api/…
alsami
3
Seperti yang ditunjukkan sebelumnya, jika Anda melewatkan untuk memanggil metode async dengan kata kunci await, Anda akan menghadapi masalah ini.
Yennefer
1
Ini bisa baik-baik saja, tetapi seseorang harus lebih berhati-hati tentang masa pakai dan cakupan resolusi yang diinginkan dari akses data daripada dengan angkuh menggunakan transien tanpa nuansa keadaan. Bahkan, saya menganggap jarang orang menginginkan konteks data sementara. Jika ruang lingkup unit kerja adalah sesuatu yang melibatkan lebih dari satu operasi data, cakupan transaksi harus mencakup lebih dari itu. Resolusi konteks data Anda harus mencerminkan cakupan unit kerja Anda. Ini adalah sesuatu yang harus dipikirkan dan ini bukan jawaban satu ukuran untuk semua.
Dave Rael
3
@alsami kamu adalah pahlawanku. 6 jam debugging yang menyakitkan. Inilah solusinya. Jika orang lain menyuntikkan IHttpContextAccessor ke dalam DbContext dan Klaimnya null, inilah solusinya. Terima kasih banyak.
jcmontx
62

Dalam beberapa kasus, kesalahan ini terjadi saat memanggil metode asinkron tanpa awaitkata kunci, yang dapat diselesaikan dengan mudah dengan menambahkan awaitsebelum pemanggilan metode. Namun, jawabannya mungkin tidak terkait dengan pertanyaan yang disebutkan tetapi dapat membantu memecahkan kesalahan yang serupa.

Hamid Nasirloo
sumber
5
Ini terjadi pada saya. Mengubah First()menjadi await / FirstAsync()bekerja.
Guilherme
Suara positif. Lihat juga jimlynn.wordpress.com/2017/11/16/… Jim Lynn "KESALAHAN KERANGKA ENTITAS: PENGOPERASIAN KEDUA YANG DIMULAI PADA KONTEKS INI SEBELUM PENGOPERASIAN SEBELUMNYA SELESAI. ANGGOTA INSTANSI APA PUN TIDAK DIJAMIN AMAN."
granadaCoder
Terima kasih untuk ini! Inilah sebenarnya masalah saya ... Lupa menambahkan menunggu di mdethod asinkron.
AxleWack
Terjadi pada saya juga, dan komentar ini membantu ketika saya mencari di mana saya lupa menunggu. Setelah saya menemukannya, masalah terpecahkan.
Sion Hai
ini berhasil untuk saya, terima kasih banyak
zoha_sh
43

Pengecualian berarti _contextsedang digunakan oleh dua thread pada saat yang bersamaan; baik dua utas dalam permintaan yang sama, atau dengan dua permintaan.

Apakah _contextstatis yang Anda nyatakan mungkin? Seharusnya tidak.

Atau apakah Anda menelepon GetClientsbeberapa kali dalam permintaan yang sama dari tempat lain dalam kode Anda?

Anda mungkin sudah melakukan ini, tetapi idealnya, Anda akan menggunakan injeksi ketergantungan untuk Anda DbContext, yang berarti Anda akan menggunakan AddDbContext()di Startup.cs Anda, dan konstruktor pengontrol Anda akan terlihat seperti ini:

private readonly MyDbContext _context; //not static

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

Jika kode Anda tidak seperti ini, tunjukkan kepada kami dan mungkin kami dapat membantu lebih lanjut.

Gabriel Luci
sumber
1
Mungkin itu pekerjaan yang saya miliki. Saya berhasil menyelesaikan, lihat jawaban saya. Tapi saya tandai milik Anda sebagai yang benar
André Luiz
Kode saya persis seperti ini dan kami sering melacak "Operasi kedua dimulai pada konteks ini sebelum operasi asinkron sebelumnya selesai. Gunakan 'await' untuk memastikan bahwa setiap operasi asinkron telah selesai sebelum memanggil metode lain dalam konteks ini. Setiap anggota instance tidak dijamin aman untuk thread. - di System.Data.Entity.Internal.ThrowingMonitor.EnsureNotEntered () ".
NMathur
@NMathur Apakah Anda menggunakan _contextobjek Anda di utas lain? Seperti di dalam Task.Run()misalnya?
Gabriel Luci
@GabrielLuci semua metode saya asinkron seperti di bawah ini, apakah ini akan menyebabkan masalah. Pengetahuan saya tentang topik ini sangat sedikit. Dapatkah Anda menyarankan di mana dan apa yang harus saya baca secara detail untuk memahami perilaku ini? public async Tugas <List <Item>> GetItems (int orderId) {List <Item> items = await _context.Item.Where (x => x.OrderId == orderId) .ToListAsync (); mengembalikan barang; }
NMathur
@Nur Itu terlihat baik-baik saja. Pastikan Anda selalu menggunakan awaitdengan metode async. Jika Anda tidak menggunakannya await, Anda dapat secara tidak sengaja masuk ke multi-threading.
Gabriel Luci
11
  • Selesaikan masalah saya menggunakan baris kode ini di file Startup.cs saya.
    Menambahkan layanan transien berarti bahwa setiap kali layanan diminta, instance baru dibuat saat Anda bekerja dengan injeksi Ketergantungan

           services.AddDbContext<Context>(options =>
                            options.UseSqlServer(_configuration.GetConnectionString("ContextConn")),
                 ServiceLifetime.Transient);
    
Muhammad Armaghan
sumber
Metode ini akan menimbulkan masalah jika jumlah transaksi instan multi-pengguna tinggi.
hakantopuz
11

Saya memiliki masalah yang sama dan ternyata pelayanan orang tua adalah singelton. Jadi konteksnya otomatis menjadi singelton juga. Meskipun telah dinyatakan sebagai Per Life Time Scoped di DI.

Menyuntikkan layanan dengan masa pakai yang berbeda ke yang lain

  1. Jangan pernah memasukkan layanan Scoped & Transient ke dalam layanan Singleton. (Ini secara efektif mengubah layanan transient atau cakupan menjadi singleton.)

  2. Jangan pernah memasukkan layanan Transient ke dalam layanan cakupan (Ini mengubah layanan transien menjadi cakupan.)

DiPix
sumber
ini adalah masalah saya tepatnya
Jonesopolis
Ini juga masalahku. Saya mendaftarkan kelas penangan sebagai tunggal, dan DbContext sebagai sementara. Saya harus menggunakan ServiceProvider dalam kelas Handler untuk mendapatkan contoh transient dari kontainer DI setiap kali Handler
dipukul
6

Saya pikir jawaban ini masih dapat membantu seseorang dan menghemat berkali-kali. Saya memecahkan masalah serupa dengan mengubah IQueryableke List(atau ke array, collection ...).

Sebagai contoh:

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

untuk

var list=_context.table1.where(...).ToList(); //or ToArray()...
Makhidi Masimov
sumber
3
IMHO, Jawaban ini tidak pantas mendapatkan poin minus, Itu hanya diungkapkan dengan buruk. .ToList () memang memecahkan sebagian besar masalah "operasi kedua ..." karena fakta bahwa itu memaksa evaluasi langsung dari ekspresi. Dengan cara ini tidak ada operasi konteks antrian.
vassilag
1
Ini adalah masalah dalam kasus saya. Saya memiliki xxx.Contains (z.prop) di klausa where dari kueri. xxx seharusnya menjadi larik int [] berbeda yang diselesaikan dari kueri sebelumnya. Sayangnya, pada saat kueri kedua muncul, xxx masih merupakan IQuerable. Menambahkan xxx.ToArray () sebelum kueri kedua memperbaiki masalah saya.
Jason Butera
5

Saya mengalami kesalahan yang sama. Itu terjadi karena saya menyebut metode yang dibangun sebagai public async void ...pengganti public async Task ....

Raynlaze
sumber
2

Saya menghadapi masalah yang sama tetapi alasannya bukan dari yang tercantum di atas. Saya membuat tugas, membuat ruang lingkup di dalam tugas dan meminta wadah untuk mendapatkan layanan. Itu berfungsi dengan baik tetapi kemudian saya menggunakan layanan kedua di dalam tugas dan saya lupa juga memintanya ke ruang lingkup baru. Karena itu, layanan ke-2 menggunakan DbContext yang sudah dibuang.

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.
            ...
        }
    }

Saya seharusnya melakukan ini:

var otherProductService = scope.ServiceProvider.GetService<IProductService>();
otherProductService.DoSomething();
Francisco Goldenstein
sumber
Bukankah konteksnya hanya akan diekspos setelah semua yang ada di blok using telah menyelesaikan eksekusi?
Sello Mkantjwa
Ketika tindakan dibuang, semuanya dibuang dalam ruang lingkup itu. Jika Anda memiliki tugas yang berjalan di latar belakang dan tugas itu lebih panjang dari tindakannya, Anda akan mengalami masalah ini kecuali jika Anda membuat cakupan baru untuk tugas tersebut, seperti yang saya lakukan di contoh. Di sisi lain, jika tugas Anda bisa memakan waktu lama atau Anda ingin 100% yakin bahwa itu akan berjalan, Anda mungkin perlu menggunakan antrian. Jika Anda menggunakan Azure, Anda dapat menggunakan antrian Bus Layanan.
Francisco Goldenstein
2

Situasi saya berbeda: Saya mencoba memasukkan database dengan 30 pengguna, termasuk dalam peran tertentu, jadi saya menjalankan kode ini:

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

Ini adalah fungsi Sinkronisasi. Di dalamnya saya memiliki 3 panggilan ke:

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

Saat saya ganti .Resultdengan .GetAwaiter().GetResult(), error ini hilang.

Catalin
sumber
2

Entity Framework Core tidak mendukung beberapa operasi paralel yang dijalankan pada DbContextinstance yang sama . Ini mencakup eksekusi asynckueri paralel dan penggunaan konkuren eksplisit apa pun dari beberapa utas. Oleh karena itu, selalu await asyncpanggil segera, atau gunakan DbContextinstance terpisah untuk operasi yang dijalankan secara paralel.

Ehsan Gondal
sumber
1

Saya memiliki layanan latar belakang yang melakukan tindakan untuk setiap entri dalam tabel. Masalahnya adalah, jika saya mengulang dan mengubah beberapa data semua pada contoh yang sama dari DbContext kesalahan ini terjadi.

Salah satu solusi, seperti yang disebutkan di utas ini adalah mengubah masa pakai DbContext menjadi sementara dengan mendefinisikannya seperti

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

tetapi karena saya melakukan perubahan di berbagai layanan dan melakukan perubahan sekaligus menggunakan SaveChanges() metode solusi ini tidak berfungsi dalam kasus saya.

Karena kode saya berjalan di layanan, saya melakukan sesuatu seperti

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

untuk dapat menggunakan layanan ini seperti permintaan sederhana. Jadi untuk mengatasi masalah ini saya hanya membagi satu lingkup menjadi dua, satu untuk kueri dan yang lainnya untuk operasi tulis seperti:

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

Seperti itu, ada dua contoh berbeda dari DbContext yang digunakan secara efektif.

Solusi lain yang mungkin adalah memastikan, bahwa operasi baca telah dihentikan sebelum memulai iterasi. Itu tidak terlalu praktis dalam kasus saya karena mungkin ada banyak hasil yang semuanya perlu dimuat ke memori untuk operasi yang saya coba hindari dengan menggunakan Querizable di tempat pertama.

NiPfi
sumber
1

Pertama, beri suara positif (setidaknya) jawaban alsami. Itu membuat saya berada di jalan yang benar.

Namun bagi Anda yang melakukan IoC, berikut adalah penjelasan yang lebih mendalam.

Kesalahan saya (sama seperti yang lain)

Terjadi satu atau lebih kesalahan. (Operasi kedua dimulai pada konteks ini sebelum operasi sebelumnya selesai. Hal ini biasanya disebabkan oleh utas yang berbeda menggunakan contoh DbContext yang sama. Untuk informasi selengkapnya tentang cara menghindari masalah threading dengan DbContext, lihat https://go.microsoft.com / fwlink /? linkid = 2097913. )

Pengaturan kode saya. "Hanya dasar-dasarnya" ...

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

dan

public interface IMySpecialObjectDomainData{}

dan (catatan MyCoolDbContext sedang diinjeksi)

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

dan

public interface IMySpecialObjectManager{}

dan

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

Dan akhirnya, kelas multi utas saya, dipanggil dari Aplikasi Konsol (aplikasi Antarmuka Baris Perintah)

    public interface IMySpecialObjectThatSpawnsThreads{}

dan

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

dan penumpukan DI. (Sekali lagi, ini untuk aplikasi konsol (antarmuka baris perintah) ... yang menunjukkan perilaku yang sedikit berbeda dari aplikasi web)

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;
}

Yang mengejutkan saya adalah (perubahan ke) sementara untuk

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

Catatan, saya pikir karena IMySpecialObjectManager disuntikkan ke "MySpecialObjectThatSpawnsThreads", objek yang disuntikkan itu harus Transient untuk menyelesaikan rantai.

Intinya adalah ....... bukan hanya Konteks Db (Saya) yang membutuhkan .Transient ... tetapi sebagian besar Grafik DI.

Tip Debugging:

Garis ini:

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

Tempatkan break point debugger Anda di sana. Jika MySpecialObjectThatSpawnsThreads Anda membuat N jumlah utas (katakanlah 10 utas misalnya) ...... dan baris itu hanya terkena sekali ... itu masalah Anda. DbContext Anda melintasi utas.

BONUS:

Saya akan menyarankan membaca ini di bawah url / artikel (lama tapi bagus) tentang perbedaan aplikasi web dan aplikasi konsol

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

Berikut adalah tajuk artikel jika tautan berubah.

MENGELOLA DBCONTEXT DENGAN BENAR DENGAN KERANGKA ENTITY 6: PANDUAN DALAM KEDALAMAN Mehdi El Gueddari

Saya mengalami masalah ini dengan WorkFlowCore https://github.com/danielgerlag/workflow-core

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

contoh kode di bawah .. untuk membantu pencari internet di masa mendatang

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

            }
        }
    }

dan

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);
                }
granadaCoder
sumber
0

Saya mendapatkan pesan yang sama. Tapi itu tidak masuk akal dalam kasus saya. Masalah saya adalah saya menggunakan properti "NotMapped" secara tidak sengaja. Ini mungkin hanya berarti kesalahan sintaks Linq atau kelas model dalam beberapa kasus. Pesan kesalahan tampaknya menyesatkan. Arti asli dari pesan ini adalah Anda tidak dapat memanggil async pada dbcontext yang sama lebih dari sekali dalam permintaan yang sama.

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

Anda dapat memeriksa tautan ini untuk detailnya, https://www.softwareblogs.com/Posts/Details/5/error-a-second-operation-started-on-this-context-before-a-previous-operation-completed

Sharon Zhou
sumber
0

Saya mendapat masalah yang sama ketika saya mencoba menggunakan FirstOrDefaultAsync() metode async pada kode di bawah ini. Dan ketika saya memperbaikinya FirstOrDefault()- masalahnya sudah terpecahkan!

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

        int userId = _context.Users
            .Where(u => u.UserName == Options.UserName)
            .FirstOrDefaultAsync()
            .Id;
...
JuSik 404
sumber
2
Ini sama sekali tidak terkait dengan FirstOrDefault () atau FirstOrDefaultAsync (). Ini tentang penggunaan dbContext.
sajadre
0

Saya berhasil mendapatkan kesalahan itu dengan meneruskan IQueryableke metode yang kemudian menggunakan 'daftar' IQuerable itu sebagai bagian dari kueri lain ke konteks yang sama.

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

Untuk menghentikan itu terjadi, saya menggunakan pendekatan di sini dan mewujudkan daftar itu sebelum meneruskannya ke metode kedua, dengan mengubah panggilan SecondMethodmenjadiSecondMethod(stockItems.ToList()

tomRedox
sumber
Ini menyelesaikan masalah, tetapi bukankah ini akan memperlambat kinerja, Apakah ada solusi alternatif?
Dheeraj Kumar
0

Dalam kasus saya, saya menggunakan komponen template di Blazor.

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

Masalahnya adalah memanggil metode (Hitung) di header komponen. Untuk mengatasi masalah saya mengubahnya seperti ini:

int total = MyList.Count();

dan nanti:

<BTable ID="Table1" TotalRows="total">
Ali Borjian
sumber
0

Saya tahu masalah ini telah ditanyakan dua tahun lalu, tetapi saya baru saja mengalami masalah ini dan perbaikan yang saya gunakan sangat membantu.

Jika Anda melakukan dua kueri dengan Konteks yang sama - Anda mungkin perlu menghapus AsNoTracking. Jika Anda menggunakan, AsNoTrackingAnda membuat pembaca data baru untuk setiap bacaan. Dua pembaca data tidak dapat membaca data yang sama.

Cornelis de Jager
sumber
0

Dalam kasus saya, saya menggunakan kunci yang tidak mengizinkan penggunaan await dan tidak membuat peringatan kompiler ketika Anda tidak menunggu async.

Masalah:

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

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

Cara mengatasinya: Tunggu asinkron di dalam kunci dengan membuatnya memblokir dengan .Wait ()

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

Kasus lain yang mungkin: jika Anda menggunakan koneksi langsung, jangan lupa untuk menutup if. Saya perlu menjalankan kueri SQL sewenang-wenang, dan membaca hasilnya. Ini adalah perbaikan cepat, saya tidak ingin menentukan kelas data, tidak mengatur koneksi SQL "normal". Jadi cukup saya menggunakan kembali koneksi database EFC sebagai var connection = Context.Database.GetDbConnection() as SqlConnection. Pastikan Anda menelepon connection.Close()sebelum melakukannya Context.SaveChanges().

klenium
sumber
-2

Jika metode Anda mengembalikan sesuatu, Anda dapat mengatasi kesalahan ini dengan .Resultmengakhiri pekerjaan dan .Wait()jika tidak mengembalikan apa pun.

Hasan_H
sumber
-6

Saya baru saja berhasil membuatnya bekerja lagi. Ini tidak masuk akal tetapi berhasil:

  1. Hapus Hangfire dari StartUp (Saya membuat pekerjaan saya di sana)
  2. Menghapus database hangfire
  3. Mulai ulang server

Saya akan menyelidiki lebih lanjut nanti tetapi metode yang saya panggil dengan hangfire menerima DBContext dan itulah kemungkinan penyebabnya.

André Luiz
sumber