비동기 '페이징'EF 선택의 처리 방법 선택 결과 선택
-
21-12-2019 - |
문제
SQL Server에서 Azure 대기열에 레코드를로드하는 것을 작성했습니다. 선택 결과의 항목의 수는 매우 크게 될 수 있으므로 데이터가 계속 검색되는 동안 큐를 시작하고 싶습니다.
EF6 (Async), 모든 Async 메소드 및 tpl ™ quequeueing. 그래서 나는 가지고 있습니다 :
// This defines queue that Generator will publsh to and
// QueueManager wil read from. More info:
// http://msdn.microsoft.com/en-us/library/hh228601(v=vs.110).aspx
var queue = new BufferBlock<ProcessQueueItem>();
// Configure queue listener first
var result = this.ReceiveAndEnqueue(queue);
// Start generation process
var tasks = generator.Generate(batchId);
.
receiveandenqueue는 간단합니다 :
private async Task ReceiveAndEnqueue(ISourceBlock<ProcessQueueItem> queue)
{
while (await queue.OutputAvailableAsync())
{
var processQueueItem = await queue.ReceiveAsync();
await this.queueManager.Enqueue(processQueueItem);
this.tasksEnqueued++;
}
}
.
생성기 생성 () 서명은 다음과 같습니다.
public void Generate(Guid someId, ITargetBlock<ProcessQueueItem> target)
.
대상의 sendasync () 메소드를 호출하여 새 항목을 배치합니다. 내가 지금하고있는 일은 총 결과 수를 '배치'로 나누고, 그대로로드하고, 모든 것을 수행 할 때까지 모든 것을 수행합니다.
public void Generate(Guid batchId, ITargetBlock<ProcessQueueItem> target)
{
var accountPromise = this.AccountStatusRepository.GetAccountsByBatchId(batchId.ToString());
accountPromise.Wait();
var accounts = accountPromise.Result;
// Batch configuration
var itemCount = accounts.Count();
var numBatches = (int)Math.Ceiling((double)itemCount / this.batchSize);
Debug.WriteLine("Found {0} items what will be put in {1} batches of {2}", itemCount, numBatches, this.batchSize);
for (int i = 0; i < numBatches; i++)
{
var itemsToTake = Math.Min(this.batchSize, itemCount - currentIndex);
Debug.WriteLine("Running batch - skip {0} and take {1}", currentIndex, itemsToTake);
// Take a subset of the items and place them onto the queue
var batch = accounts.Skip(currentIndex).Take(itemsToTake);
// Generate a list of tasks to enqueue the items
var taskList = new List<Task>(itemsToTake);
taskList.AddRange(batch.Select(account => target.SendAsync(account.AsProcessQueueItem(batchId))));
// Return the control when all tasks have been enqueued
Task.WaitAll(taskList.ToArray());
currentIndex = currentIndex + this.batchSize;
}
.
이 작동하지만, 동료는 "인터페이스를 더 간단하게 만들 수 없으며, 생성 ()을 만들고 인터페이스를 만들 수 없습니다 :
public Task<IEnumerable<ProcessQueueItem> Generate(Guid someId)
.
롯트 클리너 및 TPL 라이브러리에 생성 된 메소드의 종속성이 없습니다. 나는 완전히 동의한다, 나는 그 일을한다면, 나는 전화를 걸어라고
라고 할 것이다.var result = Generate().Wait().Result;
.
어떤 시점에서 모든 항목에 enqueuinig 전에. 그 모든 것들이 모든 물건이로드되고 메모리에있는 모든 것들을 기다릴 것입니다.
내 질문이 내려 오는 것은 다음과 같습니다. 선택에서 똑똑한 '숫자가 묻는 것처럼 ef 쿼리 결과를 사용할 수 있습니까? EF가 내 드리프트를 잡을 경우 결과를 통해 'yield'를 실행할 것입니다.
편집 나는 생각 실수를했다고 생각합니다. EF는 기본적으로 게으른 항목을로드합니다. 그래서 모든 결과를 iQueryable <>로 반환 할 수는 있지만 실제로 DB에서로드 된 것을 의미하지는 않습니다. 그런 다음 그런 다음 그들을 반복하고 그들을 대기합니다.
편집 2 Nope, 생성되지 않기 때문에 생성되지 않고 생성 된 () 메서드에서 개체를 데이터베이스에서 변환해야합니다 ...
해결책
확인, 이것은 내가 끝난 것입니다 :
public IEnumerable<ProcessQueueItem> Generate(Guid batchId)
{
var accounts = this.AccountStatusRepository.GetAccountsByBatchId(batchId.ToString());
foreach (var accountStatuse in accounts)
{
yield return accountStatuse.AsProcessQueueItem(batchId);
}
}
.
리포지토리는 일부 DataContext.stuff.where (...)의 iEnumerable을 반환합니다.발전기는 확장 메소드를 사용하여 QueueManager를 시작하기 위해 QueueManager를 호출하기 시작하여 수율의 호출자로 즉시 도메인 모델 (ProcessQueueItem)으로 엔티티를 도메인 모델 (ProcessQueueItem)으로 변환합니다.