Entity Framework Core : 이전 작업이 완료되기 전에이 컨텍스트에서 두 번째 작업이 시작되었습니다.


88

Entity Framework Core를 사용하여 ASP.Net Core 2.0 프로젝트에서 작업 중입니다.

<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 작업을 실행했지만이 작업은 동일한 엔티티를 사용하지 않습니다. 그게 내가 관련성이 있다고 생각할 수있는 전부입니다. 원인이 무엇인지에 대한 아이디어가 있습니까?



2
@Berkay 나는 그와 다른 많은 유사한 질문을보고 시도했습니다. 내 방법은 비동기 적이었고 이러한 문제를 피하기 위해 동기화했습니다. 또한 매핑을 제거하려고 시도하고 .ToPagedList를 제거하려고 시도했지만 오류가 계속 발생합니다.
André Luiz

전체 스택 추적을 보는 것이 좋을 것입니다
Evk

여러 활성 결과가 활성화되어 있는지 확인하기
Jay

동일한 문제가 발생하여 데이터베이스 테이블에 nullable 정수가 있음을 발견했습니다. 내 엔터티 모델 속성을 nullable int와 일치하도록 설정하자마자 모두 작동하기 시작했고 메시지가 오해의 소지가있었습니다 ...!
AlwaysLearning

답변:


87

IoC 및 종속성 주입을 사용하여 DbContext가 사용될 수있는 곳에서 DbContext를 해결하는지 확실하지 않습니다. .NET Core (또는 다른 IoC-Container)에서 네이티브 IoC를 사용 중이고이 오류가 발생하는 경우 DbContext를 Transient로 등록해야합니다. 하다

services.AddTransient<MyContext>();

또는

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

대신에

services.AddDbContext<MyContext>();

AddDbContext는 컨텍스트를 범위로 추가하므로 여러 스레드로 작업 할 때 문제가 발생할 수 있습니다.

또한 async / await 작업 은 비동기 람다 식을 사용할 때이 동작을 유발할 수 있습니다.

과도 상태로 추가하는 것도 단점이 있습니다. 각 클래스는 DbContext의 자체 인스턴스를 가져 오므로 컨텍스트를 사용하는 여러 클래스에 대해 일부 엔터티를 변경할 수 없습니다.

이에 대한 간단한 설명은 DbContext구현이 스레드로부터 안전하지 않다는 것입니다. 여기에서 이에 대한 자세한 내용을 읽을 수 있습니다.


1
일시적인 사용시 다음 연결 오류 (닫힘 또는 삭제) 'OmniService.DataAccess.Models.OmniServiceDbContext'가 발생합니다. System.ObjectDisposedException : 삭제 된 개체에 액세스 할 수 없습니다. 이 오류의 일반적인 원인은 종속성 주입에서 해결 된 컨텍스트를 삭제 한 다음 나중에 애플리케이션의 다른 곳에서 동일한 컨텍스트 인스턴스를 사용하려고하는 것입니다. 컨텍스트에서 Dispose ()를 호출하거나 using 문에서 컨텍스트를 래핑하는 경우 발생할 수 있습니다. ... 개체 이름 : 'AsyncDisposer'.
David

3
안녕 데이비드! 나는 당신이 Task.Run(async () => context.Set...)그것을 기다리지 않고 사용 하거나 결과를 기다리지 않고 범위가 지정된 db 컨텍스트를 만들고 있다고 생각합니다 . 이는 컨텍스트에 액세스 할 때 이미 삭제되었음을 의미합니다. Microsoft DI를 사용하는 경우 해당 .NET에서 종속성 범위를 직접 만들어야합니다 Task.Run. 이 링크도 확인하십시오. stackoverflow.com/questions/45047877/… docs.microsoft.com/en-us/dotnet/api/…
alsami

3
앞서 언급했듯이 await 키워드를 사용하여 비동기 메서드를 호출하지 않으면이 문제에 직면하게됩니다.
Yennefer

이것은 나를 도왔다. 큐에서 새 메시지를받을 때 호스팅 된 서비스의 새 스레드에 종속성을 삽입하고 있습니다. 내 컨텍스트를 일시적으로 만드는 예외 수정
Cale

3
@alsami 당신은 나의 영웅입니다. 6 시간의 고통스러운 디버깅. 이것이 해결책이었습니다. 다른 사람이 IHttpContextAccessor를 DbContext에 주입하고 클레임이 null 인 경우 이것이 해결책입니다. 정말 감사합니다.
jcmontx

55

경우에 따라이 오류 는 await키워드 없이 비동기 메서드를 호출 할 때 발생 await하며 메서드 호출 전에 추가하여 간단히 해결할 수 있습니다 . 그러나 답변이 언급 된 질문과 관련이 없을 수 있지만 유사한 오류를 해결하는 데 도움이 될 수 있습니다.


4
이것은 나에게 일어난 일입니다. 변경 First()await / FirstAsync()했다.
Guilherme 2019 년

찬성. 또한 jimlynn.wordpress.com/2017/11/16/…을 참조하십시오 . Jim Lynn " 엔티티 프레임 워크 오류 : 이전 작업이 완료 되기 전에이 컨텍스트 에서 두 번째 작업이 시작되었습니다. 모든 인스턴스 구성원이 안전한 것으로 보장되지 않습니다."
granadaCoder

감사합니다! 이것은 정확히 내 문제였습니다 ... 비동기 mdethod에 await를 추가하는 것을 잊었습니다.
AxleWack

나에게도 일어 났고,이 코멘트는 내가 누락 된 것을 잊은 곳을 찾는 데 도움이되었다. 그것을 찾으면 문제가 해결되었습니다.
Zion Hai

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()예를 들어 내부처럼 ?
Gabriel Luci

@GabrielLuci 내 모든 방법은 아래와 같이 비동기 적이므로 문제가 발생합니다. 이 주제에 대한 나의 지식은 거의 없습니다. 이러한 행동을 이해하기 위해 어디에서 무엇을 자세히 읽어야하는지 제안 해 주시겠습니까? public async Task <List <Item >> GetItems (int orderId) {List <Item> items = await _context.Item.Where (x => x.OrderId == orderId) .ToListAsync (); 반품 품목; }
NMathur

@NMathur 괜찮아 보입니다. 항상 await비동기 메서드를 사용하고 있는지 확인하십시오 . 을 사용하지 않으면 await실수로 멀티 스레딩에 들어갈 수 있습니다.
Gabriel Luci

8
  • 내 Startup.cs 파일에서이 코드 줄을 사용하여 문제를 해결하십시오.
    임시 서비스를 추가하면 서비스가 요청 될 때마다 종속성 주입으로 작업 할 때 새 인스턴스가 생성됩니다.

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

6

나는 똑같은 문제가 있었고 부모 서비스가 싱글 톤 이라는 것이 밝혀 졌습니다. 그래서 문맥도 자동적으로 singelton이되었습니다. DI에서 Per Life Time Scoped로 선언되었지만.

수명이 다른 서비스를 다른 서비스에 주입

  1. Singleton 서비스에 범위 및 임시 서비스를 삽입하지 마십시오. (이것은 일시적 또는 범위 서비스를 싱글 톤으로 효과적으로 변환합니다.)

  2. 범위가 지정된 서비스에 Transient 서비스를 주입하지 마십시오 (이는 일시적인 서비스를 범위가 지정된 서비스로 변환합니다.)


이것은 정확히 제 문제였습니다
Jonesopolis

이것도 제 문제였습니다. 핸들러 클래스를 싱글 톤으로 등록하고 DbContext를 일시적으로 등록했습니다. Handler 클래스 내에서 ServiceProvider를 사용하여 처리기가 히트 할 때마다 DI 컨테이너에서 일시적인 인스턴스를 가져와야했습니다
Daiana Sodré

5

나는 같은 오류가 있었다. public async void ...대신 으로 구성된 메서드를 호출했기 때문에 발생했습니다 public async Task ....


4

나는이 대답이 여전히 누군가를 도울 수 있고 여러 번 저장할 수 있다고 생각합니다. 나는 (또는 배열, 컬렉션 ...) 으로 변경 IQueryable하여 비슷한 문제를 해결 List했습니다.

예를 들면 :

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

...에

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

2
IMHO,이 답변은 마이너스 포인트가 필요하지 않습니다. .ToList ()는 표현식의 즉각적인 평가를 강요한다는 사실 때문에 "두 번째 작업 ..."문제의 대부분을 실제로 해결합니다. 이렇게하면 대기열 컨텍스트 작업이 없습니다.
vassilag

제 경우에는 이것이 문제였습니다. 쿼리의 where 절에 xxx.Contains (z.prop)가 있습니다. xxx는 이전 쿼리에서 확인 된 별개의 int [] 배열이어야합니다. 불행히도 두 번째 쿼리가 히트했을 때 xxx는 여전히 IQueryable이었습니다. 두 번째 쿼리 전에 xxx.ToArray ()를 추가하면 문제가 해결되었습니다.
Jason Butera

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를 사용하는 경우 Service Bus 큐를 사용할 수 있습니다.
Francisco Goldenstein

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

I 일어나는 것은 사용하는 것을 중지하려면 여기에 접근 하고 호출을 변경하여, 그것을 두 번째 방법을 전달하기 전에이 목록을 구체화 SecondMethodSecondMethod(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"에 주입 되었기 때문에 주입 된 객체는 체인을 완성하기 위해 Transient가되어야한다고 생각합니다.

요점은 ..Transient를 필요로하는 (My) DbContext 뿐만이 아니라 DI 그래프의 더 큰 덩어리였습니다.

디버깅 팁 :

이 줄 :

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

디버거 중단 점을 거기에 두십시오. MySpecialObjectThatSpawnsThreads가 N 개의 스레드를 만들고 (예 : 10 개의 스레드) ... 그 줄이 한 번만 나오면 ... 그게 문제입니다. DbContext가 스레드를 교차하고 있습니다.

보너스:

web-apps와 console-apps의 차이점에 대해 아래 URL / 기사 (오래된 것이지만 goodie)를 읽는 것이 좋습니다.

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

링크가 변경된 경우 기사의 헤더입니다.

엔티티 프레임 워크를 사용하여 올바른 방법으로 DBCONTEXT 관리 6 : 심층 가이드 Mehdi El Gueddari

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

이 문제가 2 년 전에 요청되었다는 것을 알고 있지만 방금이 문제가 있었고 내가 사용한 수정이 정말 도움이되었습니다.

동일한 컨텍스트로 두 개의 쿼리를 수행하는 경우 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

또 다른 가능한 경우 : 직접 연결을 사용하는 경우 닫는 것을 잊지 마십시오. 임의의 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. StartUp에서 Hangfire 제거 (저는 그곳에서 작업을 생성했습니다)
  2. Hangfire 데이터베이스를 삭제했습니다.
  3. 서버를 다시 시작했습니다.

나중에 자세히 조사 할 것이지만 hangfire로 호출 한 메서드는 DBContext를 수신하고 이것이 가능한 원인입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.