Erstellung eines generischen Repositories in .NET mit MongoDB
In modernen .NET-Anwendungen, die MongoDB als Datenbank verwenden, ist es eine gute Praxis, ein generisches Repository zu implementieren, um die Wiederverwendbarkeit und Wartbarkeit des Codes zu verbessern. In diesem Beitrag zeige ich, wie man ein solches Repository erstellt, das eine Methode zur Zählung von Dokumenten mit und ohne Filter bietet. Diese Methode wird in allen abgeleiteten Repositories verwendet, wodurch Code-Duplizierung vermieden wird.
1. Das Basis-Repository
Wir beginnen mit der Definition eines generischen BaseRepository
, das grundlegende CRUD-Operationen wie Create
, Read
, Update
und Delete
enthält. Außerdem fügen wir eine Methode zur Zählung von Dokumenten hinzu, die einen Filterausdruck akzeptiert. Die Zählung kann entweder mit einem spezifischen Filter oder ohne Filter durchgeführt werden.
public class BaseRepository<T>(IMongoCollection<T> collection, ILogger<BaseRepository<T>> logger) where T : class
{
protected readonly IMongoCollection<T> _collection = collection;
private readonly ILogger<BaseRepository<T>> _logger = logger;
// Zählung von Dokumenten mit einem Filterausdruck
public async Task<long> CountAsync(Expression<Func<T, bool>> filterExpression, CancellationToken cancellationToken)
{
_logger.LogInformation($"Counting {typeof(T).Name} documents with filter");
return await _collection.CountDocumentsAsync(filterExpression, cancellationToken: cancellationToken);
}
}
Erklärung:
-
_collection
: Repräsentiert die MongoDB-Kollektion für die EntitätT
. -
CountAsync
: Diese Methode zählt die Dokumente in der MongoDB-Kollektion, die dem angegebenen Filter entsprechen. Wenn kein Filter angegeben wird, kann der Filter aufx => true
gesetzt werden, was bedeutet, dass alle Dokumente gezählt werden.
2. Das abgeleitete Repository
Nun erstellen wir ein abgeleitetes Repository für eine spezifische Entität, z. B. ProductRepository
. Dieses Repository kann die CountAsync
-Methode des BaseRepository
erben und verwenden.
public class ProductRepository(IMongoCollection<Product> collection, ILogger<ProductRepository> logger) : BaseRepository<Product>(collection, logger)
{
public async Task<long> GetCountByProductIdAsync(string productId, CancellationToken cancellationToken)
{
// Zählen mit einem Filter (z. B. nach Produkt-ID)
return await _productRepository.CountAsync(x => x.ProductId == productId, cancellationToken);
}
public async Task<long> GetAllCountAsync(CancellationToken cancellationToken)
{
// Zählen ohne Filter (alle Produkte zählen)
return await CountAsync(x => true, cancellationToken);
}
// Weitere produktbezogene Methoden können hier hinzugefügt werden
}
In diesem Beispiel erbt das ProductRepository
die Funktionalität des BaseRepository
, einschließlich der Zählmethode. Es ist einfach, neue spezifische Repositories zu erstellen, die dieselbe Methode für die Zählung von Dokumenten verwenden.
Erklärung:
Zählen mit Filter
: Hier wird dieCountAsync
-Methode mit einem spezifischen Filter verwendet, um die Anzahl der Produkte mit einer bestimmten ID zu zählen.Zählen ohne Filter
: Wenn der Filterx => true
gesetzt wird, zählen wir alle Dokumente in derProduct
-Kollektion.
4. Fazit
Das Erstellen eines generischen Repositories, das grundlegende Funktionen wie das Zählen von Dokumenten bietet, ist eine sehr nützliche Technik für die Wiederverwendbarkeit und die Vereinheitlichung des Codes in einer .NET-Anwendung. Durch die Verwendung von Expression<Func<T, bool>>
als Filterausdruck ist die Flexibilität erhöht und die Methode kann in verschiedenen Szenarien wiederverwendet werden.
Die Methode CountAsync
aus dem BaseRepository
kann problemlos in verschiedenen abgeleiteten Repositories wie ProductRepository
oder CustomerRepository
verwendet werden, ohne dass redundanter Code geschrieben werden muss. Dies trägt zur Wartbarkeit und Klarheit des Codes bei, was besonders in größeren Anwendungen von Vorteil ist.