2017-11-16 3 views
0

데이터 계층에서 DbContext를 차례로 사용하는 일부 리포지토리를 사용하는 비즈니스 로직 계층에 일부 코드가 있습니다. 대부분의 코드는 비동기입니다. 내 비즈니스 로직의 어떤 시점에서, 나는 한 번 (Task.WhenAll...)) 에서 저장소의 여러 비동기 메서드를 호출하고 난 오류로 실행 A second operation started on this context before a previous asynchronous operation completedEF6에서 작업 완료를위한 DbContext 잠금

견해는, 비즈니스 로직은/치료 방법에 대한 인식해서는 안된다 리포지토리는 자신의 업무를 수행하므로 "기쁘다"면 비동기 작업에 병렬 처리를 사용할 수 있어야합니다.

A second operationprevious asynchronous operation이 완료 될 때까지 대기해야하는 중요한 순간을 비동기식/기다리기 쉬운 방식으로 잠글 수 있기를 바랍니다.

어떻게이 작업을 수행 할 수 있습니까?

현재 작업을 arround : 사용

 var postsResult = await _IUserLogic.GetActivePostsAsync(); 
     var usersResult = await _IUserLogic.SearchUsersWithPostAsync(viewModel.Name, viewModel.PostId); 

코드 존재하지 않는 TPL 같은을 기다리고 Task.WhenAll을 잊지는 각 스레드가 자신의 DbContext을 필요로

 var postsTask = _IUserLogic.GetActivePostsAsync(); 
     var usersTask = _IUserLogic.SearchUsersWithPostAsync(viewModel.Name, viewModel.PostId); 
     await Ask.WhenAll(postsTask , usersTask); 
     var postsResult = postsTask.Result; 
     var usersResult = usersTask.Result; 
+0

'DbContext'는 스레드로부터 안전한 객체가 아닙니다. 요청 당 별도의 인스턴스가 필요합니다. 쉬운 방법 중 하나는 conn 문자열을 repo에 삽입하고 요청에 따라 컨텍스트를 생성하는 것입니다. 잠금은 요청을 순차적으로 처리하는 또 하나의 방법 일 뿐이므로 요청을 차례대로 기다리는 것과 마찬가지로 여기에서 응답이되지는 않습니다. – JSteward

+0

데이터를 읽는 데 여러 DbContext를 사용하면 메모리가 흐려질 수 있습니다. 그러나 데이터 업데이트가 포함되는 즉시 간섭 (런타임 예외) 될 수 있습니다. 그래서 그것은 나를위한 실행 가능한 해결책이 아닙니다. 잠금 기능을 사용하면 전체적인 생각을 실제로 순차적으로 만들 수는 있지만 Business Logic에서는이를 처리 할 필요가 없습니다 (사용하기가 쉽다고해도 모든 곳에서 나타나야 함을 의미하지는 않습니다). 내일 데이터 원본을 병렬 읽기 (ADO.Net?)를 지원하는 것으로 변경하면 비즈니스 논리가 전체 인수 분해 없이도이를 활용하게됩니다. –

+0

비동기 잠금을 원한다면 [SemaphoreSlim] (https://docs.microsoft.com/en-us/dotnet/api/system.threading.semaphoreslim?view=netframework-4.7.1) – JSteward

답변

1

에-수 왜냐하면 DbContext는 스레드로부터 안전하지 않기 때문입니다. 그러나 여기에는 몇 가지 해결 방법이 있습니다.

  1. 각 저장소는 새로운 DbContext를 가져옵니다. 그런 식으로, 각각은 자신의 스레드에 자신의 인스턴스가 있습니다. 단일 트랜잭션이 필요하면 Transaction Scope (최신 버전은 비동기 호출을 허용)을 사용할 수 있습니다.
  2. 비즈니스 계층은 dbcontext를 각 리포지토리에 전달하고 끝에 변경 사항을 한 번 저장합니다. 각 저장소는 데이터를 DbSets에 추가하기 만하면 마지막에 단일 호출이 있습니다.
  3. (최악의 경우) 인스턴스의 DbContext에 SaveChanges를 덮어 쓰고 자신 만의 lock()을 만들어 모두 통과합니다. 그러나, 그의 목적은 Task의 목적을 거의 무효로합니다. 당신은 어쨌든 한 번에 하나씩 만 저장할 수 있기 때문에.
  4. 수행 한 작업을 개별적으로 수행하십시오.