Я новичок в делегатах, Func <> и Action <>. Я попытался прочитать несколько постов переполнения стека и документации, но безрезультатно.
Вопрос так же нацелен на то, чтобы понять, как я должен осмыслить проблему, или если я должен думать совершенно иначе. Во всяком случае здесь мы идем ...
У меня есть класс BaseRepository, подключенный к mongoDB. Ниже мы видим пример одного из методов, связанных с этим BaseClass
public async Task<IEnumerable<TEntity>> GetAll(int skip = 0, int limit = 100)
{
return await DefaultCollection
.Find(Filter.Empty)
.Skip(skip)
.Limit(limit)
.ToListAsync();
}
Что я хочу сделать, так это реализовать некоторое отслеживание, которое отслеживает время связи в истекшем миллисекунде между API и БД, чтобы я мог лучше расставить приоритеты в оптимизации. Таким образом, простой метод должен выглядеть следующим образом:
public async Task<IEnumerable<TEntity>> GetAll(int skip = 0, int limit = 100)
{
var sw = new Stopwatch();
sw.Start();
var result = await DefaultCollection
.Find(Filter.Empty)
.Skip(skip)
.Limit(limit)
.ToListAsync();
sw.Stop();
Logger.PushContext("Elapsed Milles to DB", sw.ElapsedMilliseconds);
return result;
}
Это было бы, однако, уместно записать в каждый метод, так что я задавался вопросом, какой может быть лучшая практика, и думал о том, чтобы сделать что-то вроде следующего: ПРЕДУПРЕЖДАЮЩИЙ ДОСТУП К КОДУ PSEUDO;)
public async Task<IEnumerable<TEntity>> GetAll(int skip = 0, int limit = 100)
{
return await DefaultCollection
.Find(Filter.Empty)
.Skip(skip)
.Limit(limit)
.ToListAsync();
}
/// <summary>
/// PSEUDO CODE. ONLY PSEUDO CODE
/// </summary>
/// <returns></returns>
protected async Task<TResult> ExecuteCmd(* Inject code into this method* injectedCode)
{
var sw = new Stopwatch();
sw.Start();
var result = injectedCode.Run();
sw.Stop();
Logger.PushContext("Elapsed milli to db", sw.ElapsedMilliseconds);
return result;
}
Таким образом, каждый запрос будет регистрироваться, и единственное изменение, которое я должен сделать, это поместить каждый метод в ExecuteCmd.
Может быть, что-то вроде этого:
public async Task<IEnumerable<TEntity>> GetAll(int skip = 0, int limit = 100)
{
return await ExecuteCmd(c =>
{
DefaultCollection
.Find(Filter.Empty)
.Skip(skip)
.Limit(limit)
.ToListAsync();
});
}
где этот код запускается внутри ExecuteCmd как «injectedCode.run».
Я представлял, что ExecuteCmd может принимать операторы разного типа и, соответственно, возвращать разные результаты ...
Пожалуйста, дайте мне знать, если это путь к неоднозначному. Извините, если это так, пожалуйста, дайте мне знать, если я задаю еще один подчеркивающий вопрос, чтобы я мог перефразировать.
С наилучшими пожеланиями! Заранее спасибо
Весь базовый репозиторий показан здесь для справки:
Редактировать
Для справок в будущем это обновленный базовый репозиторий, надеюсь, он может помочь другим!
public abstract class MongoReadmodelRepository<TEntity> : IMongoReadmodelRepository<TEntity> where TEntity : IEntity
{
protected readonly ILogger Logger;
protected readonly IMongoDatabase DefaultDatabase;
protected readonly string CollectionName = $"rm-{typeof(TEntity).Name.ToLower()}";
protected IMongoCollection<TEntity> DefaultCollection =>
DefaultDatabase.GetCollection<TEntity>(CollectionName);
protected UpdateDefinitionBuilder<TEntity> Update => Builders<TEntity>.Update;
protected SortDefinitionBuilder<TEntity> Sort => Builders<TEntity>.Sort;
protected FilterDefinitionBuilder<TEntity> Filter => Builders<TEntity>.Filter;
protected ProjectionDefinitionBuilder<TEntity> Projection => Builders<TEntity>.Projection;
public MongoReadmodelRepository(IMongoClient client, IOptions<ProjectionsPersistenceConfiguration> config, ILogger logger)
{
Logger = logger;
DefaultDatabase = client.GetDatabase(config.Value.DefaultProjectionsDatabaseName);
if (!CollectionExists(DefaultDatabase, CollectionName))
DefaultDatabase.CreateCollection(CollectionName);
}
public async Task<bool> Delete(Guid id)
{
Logger.Information("Trying to delete {Entity} with {Id}", typeof(TEntity).Name, id);
return (await DefaultCollection.DeleteOneAsync(Filter.Eq(x => x.Id, id)))
.IsAcknowledged;
}
public async Task<IEnumerable<TEntity>> GetAll(int skip = 0, int limit = 100)
{
return await ExecuteCmd(
() =>
DefaultCollection
.Find(Filter.Empty)
.Skip(skip)
.Limit(limit)
.ToListAsync()
);
}
public async Task<TEntity> GetByIndex(int index, int collectionSize)
{
return await DefaultCollection.Find(Filter.Empty)
.Skip(index)
.Limit(1)
.FirstOrDefaultAsync();
}
public async Task<IEnumerable<TEntity>> GetPaged(int page, int pageSize)
{
return await GetAll(page * pageSize, pageSize);
}
public async Task<TEntity> GetById(Guid id)
{
return await DefaultCollection.Find(b => b.Id == id).SingleOrDefaultAsync();
}
public async Task<Guid> Insert(TEntity entity)
{
await DefaultCollection.InsertOneAsync(entity, new InsertOneOptions());
Logger.Information("Saved {@Entity}", entity);
return entity.Id;
}
private bool CollectionExists(IMongoDatabase db, string collectionName)
{
var filter = new BsonDocument("name", collectionName);
var collections = db.ListCollections(new ListCollectionsOptions { Filter = filter });
return collections.Any();
}
protected async Task<TResult> ExecuteCmd<TResult>(Func<Task<TResult>> query)
{
var sw = new Stopwatch();
//Start stopwatch
sw.Start();
var result = await query();
sw.Stop();
Console.WriteLine("Logging execution time between API and mongoDB: Execution time in millis = " + sw.ElapsedMilliseconds);
return result;
}
}