У меня есть функция репозитория 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++;
         });
    }
0
Jeppe 14 Ноя 2018 в 10:54

1 ответ

Лучший ответ

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

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);
        }
    }
}
1
Llama 14 Ноя 2018 в 08:44