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

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



답변

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구현이 스레드로부터 안전하지 않다는 것입니다. 여기에서 이에 대한 자세한 내용을 읽을 수 있습니다.


답변

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


답변

예외 _context는 동시에 두 스레드에서 사용 중임을 의미합니다 . 동일한 요청에있는 두 개의 스레드 또는 두 개의 요청에 의해.

귀하가 _context선언 된 정적 어쩌면? 그렇지 않아야합니다.

아니면 GetClients코드의 다른 곳에서 동일한 요청으로 여러 번 호출 하고 있습니까?

이미이 일을 할 수 있지만, 이상적으로, 당신이 사용하는 것 의존성 주입 당신을 위해 DbContext사용됩니다 의미, AddDbContext()당신의 Startup.cs에, 그리고 컨트롤러 생성자는 다음과 같이 보일 것이다 :

private readonly MyDbContext _context; //not static

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

코드가 이와 같지 않다면 알려 주시면 더 많은 도움을 드릴 수 있습니다.


답변

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

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


답변

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

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

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

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


답변

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


답변

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

예를 들면 :

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

…에

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