Как запустить код на последней итерации на курсоре - PullRequest
0 голосов
/ 14 ноября 2018

У меня есть функция репозитория, GetDocs () , которая возвращает курсор MongoDB.

Где я вызываю GetDocs Я перебираю курсор и на каждой пятой итерации я вызываю SetLastId () .

Вопрос: Как определить, когда я обрабатываю последний элемент курсора, чтобы я мог вызвать SetLastId () перед выходом из цикла?

public async Task GetDocs(string id, Func<Model, Task> processor)
        {
            var filter = Builders<Model>.Filter;
            var sort = Builders<Model>.Sort;
            using (var cursor = await Coll.Find(filter.Eq(f => f.id, id)).ToCursorAsync())
            {
                foreach (var doc in cursor.Current)
                {                    
                    await processor(doc);
                }
            }
        }

.

    using (OdbcConnection conn = new OdbcConnection(context.connectionString))
    {
        conn.Open();
        int counter = 0;

        await repo.GetDocs(context.Id, async (doc) =>
         {
             if (counter % 5 == 0)
             {
                var success = await SetLastId(doc.Id);
             }
             counter++;
         });
    }

1 Ответ

0 голосов
/ 14 ноября 2018

Как насчет этого?По сути, цикл сохранит предыдущий документ в памяти и обработает его на следующей итерации.Таким образом, как только он выходит из цикла, у него есть «последний документ», который можно передать, и он может пометить его как таковой для процессора.

public async Task GetDocs(string id, Func<Model, bool, Task> processor)
{
    var filter = Builders<Model>.Filter;
    var sort = Builders<Model>.Sort;
    using (var cursor = await Coll.Find(filter.Eq(f => f.id, id)).ToCursorAsync())
    {
        Model previousDoc = null;
        foreach (var doc in cursor.Current)
        {
            if (previousDoc != null)
            {
                await processor(previousDoc, false);
            }
            previousDoc = doc;
        }
        if (previousDoc != null)
        {
            await processor(previousDoc, true);
        }
    }
}

Вы также можете заключить его в метод многократного использования, который работаетс любым IEnumerable (здесь я использовал ValueTuples , но вы можете создать свой собственный тип, если не можете их использовать):

public static IEnumerable<(T Model, bool IsLast)> Map<T>(IEnumerable<T> items)
{
    T prevModel = default(T);
    bool isFirst = true;
    foreach (var model in items)
    {
        if (!isFirst)
        {
            yield return (prevModel, false);
        }
        else
        {
            isFirst = false;
        }
        prevModel = model;
    }

    if (!isFirst)
    {
        yield return (prevModel, true);
    }
}


public async Task GetDocs(string id, Func<Model, bool, Task> processor)
{
    var filter = Builders<Model>.Filter;
    var sort = Builders<Model>.Sort;
    using (var cursor = await Coll.Find(filter.Eq(f => f.id, id)).ToCursorAsync())
    {
        foreach (var docWrapper in Map(cursor.Current))
        {
            await processor(docWrapper.Model, docWrapper.IsLast);
        }
    }
}
...