Entity Framework Core: Önceki bir işlem tamamlanmadan önce bu bağlamda ikinci bir işlem başlatıldı


98

Entity Framework Core kullanarak bir ASP.Net Core 2.0 projesi üzerinde çalışıyorum

<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"/>

Ve liste yöntemlerinden birinde bu hatayı alıyorum:

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

Bu benim yöntemim:

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

Özellikle yerel olarak çalıştırdığımda çalıştığı için biraz kayboldum, ancak hazırlama sunucuma (IIS 8.5) dağıttığımda bana bu hatayı alıyor ve normal çalışıyordu. Modellerimden birinin maksimum uzunluğunu artırdıktan sonra hata görünmeye başladı. Ayrıca ilgili Görünüm Modelinin maksimum uzunluğunu da güncelledim. Ve birbirine çok benzeyen ve işe yarayan birçok başka liste yöntemi var.

Çalışan bir Hangfire işim vardı ama bu iş aynı varlığı kullanmıyor. Alakalı olduğunu düşündüğüm tek şey bu. Buna neyin sebep olabileceğine dair herhangi bir fikriniz var mı?


1
Bunu kontrol edin .
Berkay

2
@Berkay Bunu ve daha birçok benzer soruyu gördüm ve denedim. Yöntemim zaman uyumsuzdu ve bu sorunları önlemek için onu senkronize ettim. Ayrıca eşlemeyi kaldırmaya çalışıyorum, ayrıca .ToPagedList'i kaldırmaya çalıştım, hatayı atmaya devam ediyor.
André Luiz

Tam bir yığın izleme görmek iyi olur
Evk

Ve birden çok etkin sonucun etkinleştirilip etkinleştirilmediğini bilmek için
Jay

Aynı sorunu yaşadıktan sonra, veritabanı tablomda null yapılabilir tam sayılarım olduğunu keşfettim. Varlık modeli özelliklerimi null yapılabilir int'ler ile eşleşecek şekilde ayarlar ayarlamaz, hepsi çalışmaya başladı, bu yüzden mesajlar benim için yanıltıcıydı ...!
AlwaysLearning

Yanıtlar:


98

DbContext'inizi nerede kullanılabileceği konusunda çözmek için IoC ve Bağımlılık Enjeksiyonu kullanıyor musunuz emin değilim. Bunu yapıyorsanız ve .NET Core'dan (veya başka herhangi bir IoC-Container'dan) yerel IoC kullanıyorsanız ve bu hatayı alıyorsanız, DbContext'inizi Geçici olarak kaydettiğinizden emin olun. Yapmak

services.AddTransient<MyContext>();

VEYA

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

onun yerine

services.AddDbContext<MyContext>();

AddDbContext, bağlamı kapsamlı olarak ekler, bu da birden çok iş parçacığı ile çalışırken sorunlara neden olabilir.

Ayrıca zaman uyumsuz / bekleme işlemleri , zaman uyumsuz lambda ifadeleri kullanılırken bu davranışa neden olabilir.

Geçici olarak eklemenin dezavantajları vardır. Her sınıf DbContext'inizin kendi örneğini alacağından, bağlamı kullanan birden çok sınıf üzerinde bazı varlıklarda değişiklik yapamazsınız.

Bunun basit açıklaması, DbContextuygulamanın iş parçacığı açısından güvenli olmamasıdır. Bu konuda daha fazla bilgi bulabilirsiniz burada


2
Geçici kullandığımda aşağıdaki bağlantı hatalarını (kapalı veya atılmış) alıyorum 'OmniService.DataAccess.Models.OmniServiceDbContext'. System.ObjectDisposedException: Kullanılmış bir nesneye erişilemez. Bu hatanın yaygın bir nedeni, bağımlılık ekleme işleminden çözülen bir bağlamı atmak ve daha sonra aynı bağlam örneğini uygulamanızın başka bir yerinde kullanmaya çalışmaktır. Bu, bağlamda Dispose () 'u çağırıyorsanız veya bağlamı bir using deyimi içinde kaydırıyorsanız oluşabilir. ... Nesne adı: 'AsyncDisposer'.
David

5
Merhaba David! Sanırım Task.Run(async () => context.Set...)beklemeden kullanıyorsunuz veya sonucu beklemeden kapsamlı bir db bağlamı oluşturuyorsunuz. Bu, bağlamınızın muhtemelen erişirken zaten elden çıkarıldığı anlamına gelir. Microsoft DI üzerindeyseniz, bunun içinde kendiniz bir bağımlılık kapsamı oluşturmanız gerekir Task.Run. Bu bağlantılara da göz atın. stackoverflow.com/questions/45047877/… docs.microsoft.com/en-us/dotnet/api/…
alsami

3
Daha önce de belirtildiği gibi, await anahtar sözcüğüyle eşzamansız bir yöntemi çağırmayı kaçırırsanız, bu sorunla karşılaşırsınız.
Yennefer

1
Bu iyi olabilir, ancak veri erişiminin istenen kullanım ömrü ve çözüm kapsamı hakkında, koşullar nüanssız geçici durum kullanmaktan daha dikkatli olunmalıdır. Aslında, bir veri bağlamının geçici olmasını istemenin nadir olduğunu düşünürdüm. Bir iş biriminin kapsamı tek bir veri işleminden fazlasını içeren bir şeyse, işlem kapsamı bundan daha fazlasını kapsamalıdır. Veri bağlamınızın çözümü, çalışma biriminizin kapsamını yansıtmalıdır. Bu, üzerinde düşünülmesi gereken bir şeydir ve bu, herkese uyan tek bir cevap değildir.
Dave Rael

3
@alsami sen benim kahramanımsın. 6 saat acı verici hata ayıklama. Çözüm buydu. Başka biri IHttpContextAccessor'ı DbContext'e enjekte ediyorsa ve Talepler boşsa, çözüm budur. Çok teşekkür ederim adamım
jcmontx

62

Bazı durumlarda, bu hata , anahtar kelime olmadan zaman uyumsuz bir yöntemi çağırırken meydana gelir ve bu , yöntem çağrısından önce awaiteklenerek kolayca çözülebilir await. ancak cevap bahsedilen soruyla ilgili olmayabilir ancak benzer bir hatanın çözülmesine yardımcı olabilir.


5
Bu bana oldu. Değişen First()için await / FirstAsync()çalıştı.
Guilherme

Olumlu oy verin. Ayrıca bkz jimlynn.wordpress.com/2017/11/16/… Jim Lynn "ENTITY ÇERÇEVE HATASI: ÖNCEKİ BİR İŞLEM TAMAMLANMADAN ÖNCE BU BAĞLAMDA İKİNCİ BİR İŞLEM BAŞLADI. HERHANGİ BİR INSTANCE ÜYESİ İPLİK GÜVENLİĞİ GARANTİSİ DEĞİLDİR."
granadaCoder

Bunun için teşekkürler! Bu tam olarak benim sorunumdu ... Zaman uyumsuz mdethod'a bir await eklemeyi unuttum.
AxleWack

Benim de başıma geldi ve bu yorum, eksik bir beklemeyi unuttuğum yeri araştırırken yardımcı oldu. Bulduğumda sorun çözüldü.
Zion Hai

benim için çalıştı, çok teşekkürler
zoha_sh

43

İstisna _context, aynı anda iki iş parçacığı tarafından kullanıldığı anlamına gelir ; ya aynı istekte iki iş parçacığı ya da iki istek.

_contextBeyan ettiğiniz statik olabilir mi? Olmamalı.

Veya GetClientskodunuzda başka bir yerden aynı istek içinde birden çok kez mi arıyorsunuz?

Zaten bu yapıyor olabilir, ama ideal, kullandığınız olurdu bağımlılık enjeksiyon şunlara ait DbContextkullandığınız olacak demektir, AddDbContext()senin Startup.cs 'da ve denetleyici yapıcı bu gibi bir şey olacaktır:

private readonly MyDbContext _context; //not static

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

Kodunuz böyle değilse bize gösterin ve belki daha fazla yardımcı olabiliriz.


1
Muhtemelen sahip olduğum iş bu. Çözmeyi başardım, cevabımı görün. Ama seninkini doğru olarak işaretliyorum
André Luiz

Kodum tam olarak bunun gibi ve biz sık sık izliyoruz "Önceki bir eşzamansız işlem tamamlanmadan önce bu bağlamda ikinci bir işlem başlatıldı. Bu bağlamda başka bir yöntemi çağırmadan önce zaman uyumsuz işlemlerin tamamlandığından emin olmak için 'await' kullanın. Herhangi bir örnek üye değildir. iş parçacığı için güvenli olduğu garanti. - System.Data.Entity.Internal.ThrowingMonitor.EnsureNotEntered () ".
NMathur

@NMathur Nesnenizi _contextbaşka iş parçacıklarında mı kullanıyorsunuz ? Örneğin içinde Task.Run()mi?
Gabriel Luci

@GabrielLuci tüm yöntemlerim aşağıdaki gibi async, bu soruna neden olur. Bu konuyla ilgili bilgim çok az. Bu davranışları anlamak için nerede ve neyi ayrıntılı olarak okumam gerektiğini önerebilir misiniz? public async Task <List <Item>> GetItems (int orderId) {List <Item> öğeleri = await _context.Item.Where (x => x.OrderId == orderId) .ToListAsync (); öğeleri iade edin; }
NMathur

@NMathur Bu iyi görünüyor. Her zaman awaiteşzamansız yöntemlerle kullandığınızdan emin olun . Eğer kullanmıyorsanız await, istemeden çoklu iş parçacığı içine alabilirsiniz.
Gabriel Luci

11
  • Startup.cs dosyamdaki bu kod satırını kullanarak sorunumu çözün.
    Geçici bir hizmet eklemek, hizmet her istendiğinde, Bağımlılık ekleme ile çalışırken yeni bir örnek oluşturulduğu anlamına gelir.

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

Bu yöntem, çok kullanıcılı anlık işlem sayısının fazla olduğu durumlarda sorun yaratacaktır.
hakantopuz

11

Ben de aynı sorunu yaşadım ve ebeveyn hizmetinin tek başına olduğu ortaya çıktı . Böylece bağlam da otomatik olarak tekil oldu. DI'de Yaşam Süresi Başına Kapsamlı olarak ilan edilmiş olsa da.

Farklı yaşam sürelerine sahip hizmeti diğerine enjekte etmek

  1. Kapsamlı ve Geçici hizmetleri asla Singleton hizmetine eklemeyin. (Bu, geçici veya kapsamlı hizmeti etkili bir şekilde singleton'a dönüştürür.)

  2. Geçici hizmetleri asla kapsamlı hizmete ekleme (Bu, geçici hizmeti kapsamlı hizmete dönüştürür.)


tam olarak benim sorunum
buydu

Bu benim de sorunumdu. Bir işleyici sınıfını singleton ve DbContext'i geçici olarak kaydediyordum. İşleyiciye her
vurulduğunda

6

Bu cevabın hala birisine yardımcı olabileceğini ve birçok kez kurtarabileceğini düşünüyorum. Ben değiştirerek benzer bir sorunu çözmüş IQueryableiçin List(veya dizi koleksiyonu ... kadar).

Örneğin:

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

-e

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

3
IMHO, Bu cevap eksi noktaları hak etmiyor, sadece zayıf bir şekilde ifade ediliyor. .ToList (), ifadenin hemen değerlendirilmesini zorlaması nedeniyle aslında "ikinci bir işlem ..." sorunlarının çoğunu çözer. Bu şekilde kuyruğa alma bağlamı işlemleri yoktur.
vassilag

1
Benim durumumdaki sorun buydu. Bir sorgunun where cümlesinde xxx.Contains (z.prop) vardı. xxx, önceki bir sorgudan çözülen ayrı bir int [] dizisi olması gerekiyordu. Ne yazık ki, ikinci sorgu isabet ettiğinde, xxx hala bir IQueryable idi. İkinci sorgudan önce xxx.ToArray () eklemek sorunumu çözdü.
Jason Butera

5

Ben de aynı hatayı aldım. Bunun nedeni public async void ...yerine inşa edilen bir yöntemi çağırdım public async Task ....


2

Ben de aynı sorunla karşılaştım ama nedeni yukarıda listelenenlerden hiçbiri değildi. Bir görev oluşturdum, görevin içinde bir kapsam oluşturdum ve konteynerden bir hizmet almasını istedim. Bu iyi çalıştı ama sonra görevin içinde ikinci bir hizmet kullandım ve yeni kapsam için de istemeyi unuttum. Bu nedenle, 2. hizmet zaten atılmış olan bir DbContext kullanıyordu.

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

Bunu yapmalıydım:

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

Bağlam, yalnızca kullanım bloğundaki her şeyin yürütülmesi tamamlandığında ortaya çıkmaz mı?
Sello Mkantjwa

Eylem elden çıkarıldığında, her şey bu kapsamda düzenlenir. Arka planda çalışan bir göreviniz varsa ve bu görev eylemden daha uzunsa, örnekte yaptığım gibi görev için yeni bir kapsam oluşturmazsanız bu sorunu yaşarsınız. Öte yandan, göreviniz uzun sürebilirse veya çalışacağından% 100 emin olmak istiyorsanız, bir kuyruk kullanmanız gerekebilir. Azure kullanıyorsanız, Service Bus kuyruklarını kullanabilirsiniz.
Francisco Goldenstein

2

Durumum farklı: Veritabanını belirli rollere ait 30 kullanıcıyla başlatmaya çalışıyordum, bu yüzden şu kodu çalıştırıyordum:

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

Bu bir Eşitleme işleviydi. İçinde 3 çağrı aldım:

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

Ben yerini zaman .Resultile .GetAwaiter().GetResult(), bu hata gitti.


2

Entity Framework Core, aynı DbContextörnekte çalıştırılan birden çok paralel işlemi desteklemez . Bu, hem asyncsorguların paralel yürütülmesini hem de birden çok iş parçacığından herhangi bir açık eşzamanlı kullanımı içerir. Bu nedenle, her zaman await asynchemen çağırın veya DbContextparalel olarak yürütülen işlemler için ayrı örnekler kullanın .


1

Tablodaki her giriş için bir eylem gerçekleştiren bir arka plan hizmetim var. Sorun şu ki, DbContext'in aynı örneğinde bazı verileri yineler ve değiştirirsem bu hata oluşur.

Bu iş parçacığında belirtildiği gibi bir çözüm, DbContext'in ömrünü aşağıdaki gibi tanımlayarak geçici olarak değiştirmektir.

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

ancak birden çok farklı hizmette değişiklik yaptığım ve bunları aynı anda SaveChanges()yöntemi kullanarak gerçekleştirdiğim için bu çözüm benim durumumda çalışmıyor.

Kodum bir hizmette çalıştığı için, şöyle bir şey yapıyordum

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

hizmeti basit bir talepmiş gibi kullanabilmek. Bu yüzden sorunu çözmek için tek kapsamı ikiye böldüm, biri sorgu için diğeri de böyle yazma işlemleri için:

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

Bunun gibi, kullanılan DbContext'in etkili bir şekilde iki farklı örneği vardır.

Başka bir olası çözüm, yinelemeye başlamadan önce okuma işleminin sonlandırıldığından emin olmaktır. Benim durumumda bu pek pratik değil çünkü ilk başta bir Queryable kullanarak kaçınmaya çalıştığım işlem için belleğe yüklenmesi gereken birçok sonuç olabilir.


1

İlk olarak, (en azından) alsami'nin cevabına olumlu oy verin. Bu beni doğru yola götürdü.

Ancak, IoC yapanlarınız için, işte biraz daha derin bir dalış.

Benim hatam (diğerleriyle aynı)

Bir veya daha fazla hata oluştu. (Önceki bir işlem tamamlanmadan önce bu bağlamda ikinci bir işlem başlatıldı. Bu genellikle aynı DbContext örneğini kullanan farklı iş parçacıklarından kaynaklanır. DbContext ile iş parçacığı sorunlarının nasıl önleneceği hakkında daha fazla bilgi için bkz. Https://go.microsoft.com / fwlink /? linkid = 2097913. )

Kod kurulumum. "Sadece temel bilgiler" ...

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

ve

public interface IMySpecialObjectDomainData{}

ve (MyCoolDbContext'in enjekte edildiğini unutmayın)

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

ve

public interface IMySpecialObjectManager{}

ve

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

Ve son olarak, çok iş parçacıklı sınıfım bir Konsol Uygulamasından (Komut Satırı Arayüzü uygulaması) çağrılıyor

    public interface IMySpecialObjectThatSpawnsThreads{}

ve

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

ve DI birikmesi. (Yine, bu, web uygulamalarından biraz farklı davranış gösteren bir konsol uygulaması (komut satırı arayüzü) içindir)

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

Beni şaşırtanlar, geçici olanlardı

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

Not, IMySpecialObjectManager "MySpecialObjectThatSpawnsThreads" içine enjekte edildiğinden, bu enjekte edilen nesnelerin zinciri tamamlamak için Geçici olması gerektiğini düşünüyorum.

Asıl nokta ....... gerekli olan sadece (My) DbContext değildi ... Geçici ... ama DI Graph'in daha büyük bir parçası.

Hata Ayıklama İpucu:

Bu hat:

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

Hata ayıklayıcı kırılma noktanızı oraya koyun. MySpecialObjectThatSpawnsThreads, N sayıda iş parçacığı oluşturuyorsa (örneğin 10 iş parçacığı diyelim) ...... ve bu satıra yalnızca bir kez vuruluyorsa ... bu senin sorunun. DbContext'iniz iş parçacıklarını aşıyor.

BONUS:

Web uygulamaları ve konsol uygulamaları arasındaki farklar hakkında aşağıdaki url / makaleyi (eski ama güzel) okumanızı öneririm.

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

Bağlantının değişmesi ihtimaline karşı makalenin başlığı.

DBCONTEXT'İ ENTITY ÇERÇEVESİ İLE DOĞRU YÖNETME 6: DERİNLEMESİNE DAYALI BİR KILAVUZ Mehdi El Gueddari

Bu soruna WorkFlowCore https://github.com/danielgerlag/workflow-core ile ulaştım

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

Aşağıdaki örnek kod .. gelecekteki İnternet araştırmacılarına yardımcı olmak için

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

            }
        }
    }

ve

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

Ben de aynı mesajı aldım. Ama benim durumumda hiç mantıklı değil. Sorunum, yanlışlıkla "NotMapped" özelliğini kullanmam. Muhtemelen sadece bazı durumlarda Linq sözdizimi veya model sınıfı hatası anlamına gelir. Hata mesajı yanıltıcı görünüyor. Bu mesajın orijinal anlamı, aynı db bağlamında aynı istekte birden fazla kez eşzamansız çağrı yapamazsınız.

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

Ayrıntılı bilgi için bu bağlantıyı kontrol edebilirsiniz, https://www.softwareblogs.com/Posts/Details/5/error-a-second-operation-started-on-this-context-before-a-previous-operation-completed


0

FirstOrDefaultAsync() Aşağıdaki kodda async yönteminde kullanmaya çalıştığımda da aynı sorunu yaşadım . Ve düzelttiğimde FirstOrDefault()- sorun çözüldü!

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

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

2
FirstOrDefault () veya FirstOrDefaultAsync () ile hiç ilgili değildir. DbContext'in kullanımı ile ilgilidir.
sajadre

0

Bu hatayı IQueryable, daha sonra bu IQueryable 'listesini' aynı bağlamda başka bir sorgunun parçası olarak kullanan bir yönteme geçirerek almayı başardım .

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

Bunu durdurmak için buradaki yaklaşımı kullandım ve ikinci yöntemi geçmeden önce bu listeyi SecondMethodbe çağrısını değiştirerek gerçekleştirdim .SecondMethod(stockItems.ToList()


Bu sorunu çözdü, ancak bu performansı yavaşlatmaz, Alternatif bir çözüm var mı?
Dheeraj Kumar

0

Benim durumumda Blazor'da bir şablon bileşeni kullanıyorum.

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

Sorun, bileşen başlığında bir yöntem (Count) çağırmaktır. Sorunu çözmek için şu şekilde değiştirdim:

int total = MyList.Count();

ve sonra :

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

0

Bu sorunun iki yıl önce sorulduğunu biliyorum, ancak bu sorunu yeni yaşadım ve kullandığım düzeltme gerçekten yardımcı oldu.

Aynı Bağlamla iki sorgu yapıyorsanız - AsNoTracking. Eğer kullanırsanız AsNoTracking, her okuma için yeni bir veri okuyucu oluşturursunuz. İki veri okuyucu aynı verileri okuyamaz.


0

Benim durumumda, await kullanımına izin vermeyen ve bir asenkron beklemediğinizde derleyici uyarısı oluşturmayan bir kilit kullanıyordum.

Sorun:

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

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

Düzeltme: Bir .Wait () ile bloke ederek kilidin içinde zaman uyumsuz olanı bekleyin.

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

0

Başka bir olası durum: doğrudan bağlantıyı kullanırsanız, kapatmayı unutmayın. Rasgele SQL sorgusu yürütmem ve sonucu okumam gerekiyordu. Bu hızlı bir çözümdü, bir veri sınıfı tanımlamak istemedim, "normal" SQL bağlantısı kurmak istemedim. Bu yüzden basitçe EFC'nin veritabanı bağlantısını olarak yeniden kullandım var connection = Context.Database.GetDbConnection() as SqlConnection. Aramadan connection.Close()önce aradığınızdan emin olun Context.SaveChanges().


-2

Yönteminiz bir şeyi geri veriyorsa, bu hatayı .Resultişin sonuna koyarak ve .Wait()herhangi bir şey döndürmezse çözebilirsiniz .


-6

Sadece tekrar çalıştırmayı başardım. Çok mantıklı değil ama işe yaradı:

  1. Hangfire'ı Başlangıçtan Kaldır (işimi orada oluşturuyordum)
  2. Hangfire veritabanı silindi
  3. Sunucuyu yeniden başlattı

Daha sonra araştıracağım, ancak hangfire ile çağırdığım yöntem bir DBContext alıyor ve olası neden bu.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.