253 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			253 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using MongoDB.Bson;
 | |
| using MongoDB.Driver;
 | |
| using MongoDB.Driver.Linq;
 | |
| using System.Linq.Expressions;
 | |
| using System.Reflection;
 | |
| 
 | |
| namespace Core.Blueprint.Mongo
 | |
| {
 | |
|     /// <summary>
 | |
|     /// Provides methods for interacting with a MongoDB collection for a specific document type.
 | |
|     /// Inherits from <see cref="MongoProvider"/> and implements <see cref="ICollectionsRepository{TDocument}"/>.
 | |
|     /// This class encapsulates common database operations such as querying, inserting, updating, and deleting documents.
 | |
|     /// </summary>
 | |
|     /// <typeparam name="TDocument">The type of document stored in the collection, which must implement <see cref="IDocument"/>.</typeparam>
 | |
|     public class CollectionRepository<TDocument>(IMongoDatabase database) : ICollectionsRepository<TDocument> where TDocument : IDocument
 | |
|     {
 | |
|         private IMongoCollection<TDocument> _collection;
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Initializes the MongoDB collection based on the <see cref="CollectionAttributeName"/> attribute
 | |
|         /// applied to the <typeparamref name="TDocument"/> type. Throws an exception if the attribute is not present.
 | |
|         /// </summary>
 | |
|         public void CollectionInitialization()
 | |
|         {
 | |
|             var collectionAttribute = typeof(TDocument).GetCustomAttribute<CollectionAttributeName>();
 | |
|             if (collectionAttribute == null)
 | |
|             {
 | |
|                 throw new InvalidOperationException($"The class {typeof(TDocument).Name} is missing the CollectionAttributeName attribute.");
 | |
|             }
 | |
| 
 | |
|             string collectionName = collectionAttribute.Name;
 | |
| 
 | |
|             _collection = database.GetCollection<TDocument>(collectionName);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Returns all documents from the collection as an enumerable list.
 | |
|         /// </summary>
 | |
|         /// <returns>A task that represents the asynchronous operation. The task result contains an enumerable list of documents.</returns>
 | |
|         public virtual async ValueTask<IEnumerable<TDocument>> AsQueryable()
 | |
|         {
 | |
|             return await _collection.AsQueryable().ToListAsync();
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Filters documents in the collection based on the provided filter expression.
 | |
|         /// </summary>
 | |
|         /// <param name="filterExpression">A lambda expression that defines the filter criteria for the documents.</param>
 | |
|         /// <returns>A task that represents the asynchronous operation. The task result contains a list of documents that match the filter.</returns>
 | |
|         public virtual async Task<IEnumerable<TDocument>> FilterBy(
 | |
|             Expression<Func<TDocument, bool>> filterExpression)
 | |
|         {
 | |
|             var objectResult = await _collection.FindAsync(filterExpression).ConfigureAwait(false);
 | |
|             return objectResult.ToList();
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Filters documents in the collection based on the provided filter and projection expressions.
 | |
|         /// Projects the filtered documents into a new type.
 | |
|         /// </summary>
 | |
|         /// <typeparam name="TProjected">The type to project the documents into.</typeparam>
 | |
|         /// <param name="filterExpression">A lambda expression that defines the filter criteria for the documents.</param>
 | |
|         /// <param name="projectionExpression">A lambda expression that defines how the documents should be projected.</param>
 | |
|         /// <returns>An enumerable collection of projected documents.</returns>
 | |
|         public virtual IEnumerable<TProjected> FilterBy<TProjected>(
 | |
|             Expression<Func<TDocument, bool>> filterExpression,
 | |
|             Expression<Func<TDocument, TProjected>> projectionExpression)
 | |
|         {
 | |
|             return _collection.Find(filterExpression).Project(projectionExpression).ToEnumerable();
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Finds a single document that matches the provided filter expression.
 | |
|         /// </summary>
 | |
|         /// <param name="filterExpression">A lambda expression that defines the filter criteria for the document.</param>
 | |
|         /// <returns>The document that matches the filter, or <c>null</c> if no document is found.</returns>
 | |
|         public virtual TDocument FindOne(Expression<Func<TDocument, bool>> filterExpression)
 | |
|         {
 | |
|             return _collection.Find(filterExpression).FirstOrDefault();
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Filters documents in the collection based on the provided MongoDB filter definition.
 | |
|         /// </summary>
 | |
|         /// <param name="filterDefinition">A filter definition for MongoDB query.</param>
 | |
|         /// <returns>A task that represents the asynchronous operation. The task result contains a list of documents that match the filter.</returns>
 | |
|         public virtual async Task<IEnumerable<TDocument>> FilterByMongoFilterAsync(FilterDefinition<TDocument> filterDefinition)
 | |
|         {
 | |
|             var objectResult = await _collection.Find(filterDefinition).ToListAsync().ConfigureAwait(false);
 | |
|             return objectResult;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Asynchronously finds a single document that matches the provided filter expression.
 | |
|         /// </summary>
 | |
|         /// <param name="filterExpression">A lambda expression that defines the filter criteria for the document.</param>
 | |
|         /// <returns>A task that represents the asynchronous operation. The task result contains the document that matches the filter, or <c>null</c> if no document is found.</returns>
 | |
|         public virtual Task<TDocument> FindOneAsync(Expression<Func<TDocument, bool>> filterExpression)
 | |
|         {
 | |
|             return Task.Run(() => _collection.Find(filterExpression).FirstOrDefaultAsync());
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Finds a document by its unique identifier (ID).
 | |
|         /// </summary>
 | |
|         /// <param name="id">The unique identifier of the document.</param>
 | |
|         /// <returns>The document that matches the specified ID, or <c>null</c> if no document is found.</returns>
 | |
|         public virtual TDocument FindById(string id)
 | |
|         {
 | |
|             var filter = Builders<TDocument>.Filter.Eq(doc => doc._Id, id);
 | |
|             return _collection.Find(filter).SingleOrDefault();
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Asynchronously finds a document by its unique identifier (ID).
 | |
|         /// </summary>
 | |
|         /// <param name="id">The unique identifier of the document.</param>
 | |
|         /// <returns>A task that represents the asynchronous operation. The task result contains the document that matches the specified ID, or <c>null</c> if no document is found.</returns>
 | |
|         public virtual Task<TDocument> FindByIdAsync(string id)
 | |
|         {
 | |
|             return Task.Run(() =>
 | |
|             {
 | |
|                 var objectId = new ObjectId(id);
 | |
|                 var filter = Builders<TDocument>.Filter.Eq(doc => doc._Id, id);
 | |
|                 return _collection.Find(filter).SingleOrDefaultAsync();
 | |
|             });
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Inserts a single document into the collection.
 | |
|         /// </summary>
 | |
|         /// <param name="document">The document to insert.</param>
 | |
|         public virtual void InsertOne(TDocument document)
 | |
|         {
 | |
|             _collection.InsertOne(document);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Asynchronously inserts a single document into the collection.
 | |
|         /// </summary>
 | |
|         /// <param name="document">The document to insert.</param>
 | |
|         /// <returns>A task that represents the asynchronous operation.</returns>
 | |
|         public virtual Task InsertOneAsync(TDocument document)
 | |
|         {
 | |
|             return Task.Run(() => _collection.InsertOneAsync(document));
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Inserts multiple documents into the collection.
 | |
|         /// </summary>
 | |
|         /// <param name="documents">The collection of documents to insert.</param>
 | |
|         public void InsertMany(ICollection<TDocument> documents)
 | |
|         {
 | |
|             _collection.InsertMany(documents);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Asynchronously inserts multiple documents into the collection.
 | |
|         /// </summary>
 | |
|         /// <param name="documents">The collection of documents to insert.</param>
 | |
|         /// <returns>A task that represents the asynchronous operation.</returns>
 | |
|         public virtual async Task InsertManyAsync(ICollection<TDocument> documents)
 | |
|         {
 | |
|             await _collection.InsertManyAsync(documents);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Replaces an existing document in the collection.
 | |
|         /// </summary>
 | |
|         /// <param name="document">The document with the updated data.</param>
 | |
|         public void ReplaceOne(TDocument document)
 | |
|         {
 | |
|             var filter = Builders<TDocument>.Filter.Eq(doc => doc._Id, document._Id);
 | |
|             _collection.FindOneAndReplace(filter, document);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Asynchronously replaces an existing document in the collection.
 | |
|         /// </summary>
 | |
|         /// <param name="document">The document with the updated data.</param>
 | |
|         /// <returns>A task that represents the asynchronous operation.</returns>
 | |
|         public virtual async Task ReplaceOneAsync(TDocument document)
 | |
|         {
 | |
|             var filter = Builders<TDocument>.Filter.Eq(doc => doc._Id, document._Id);
 | |
|             await _collection.FindOneAndReplaceAsync(filter, document);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Deletes a single document from the collection based on the provided filter expression.
 | |
|         /// </summary>
 | |
|         /// <param name="filterExpression">A lambda expression that defines the filter criteria for the document to delete.</param>
 | |
|         public void DeleteOne(Expression<Func<TDocument, bool>> filterExpression)
 | |
|         {
 | |
|             _collection.FindOneAndDelete(filterExpression);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Asynchronously deletes a single document from the collection based on the provided filter expression.
 | |
|         /// </summary>
 | |
|         /// <param name="filterExpression">A lambda expression that defines the filter criteria for the document to delete.</param>
 | |
|         /// <returns>A task that represents the asynchronous operation.</returns>
 | |
|         public async Task<TDocument> DeleteOneAsync(Expression<Func<TDocument, bool>> filterExpression)
 | |
|         {
 | |
|             return await _collection.FindOneAndDeleteAsync(filterExpression);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Deletes a single document from the collection based on its unique identifier (ID).
 | |
|         /// </summary>
 | |
|         /// <param name="id">The unique identifier of the document to delete.</param>
 | |
|         public void DeleteById(string id)
 | |
|         {
 | |
|             var objectId = new ObjectId(id);
 | |
|             var filter = Builders<TDocument>.Filter.Eq(doc => doc._Id, id);
 | |
|             _collection.FindOneAndDelete(filter);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Asynchronously deletes a single document from the collection based on its unique identifier (ID).
 | |
|         /// </summary>
 | |
|         /// <param name="id">The unique identifier of the document to delete.</param>
 | |
|         /// <returns>A task that represents the asynchronous operation.</returns>
 | |
|         public Task DeleteByIdAsync(string id)
 | |
|         {
 | |
|             return Task.Run(() =>
 | |
|             {
 | |
|                 var objectId = new ObjectId(id);
 | |
|                 var filter = Builders<TDocument>.Filter.Eq(doc => doc._Id, id);
 | |
|                 _collection.FindOneAndDeleteAsync(filter);
 | |
|             });
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Deletes multiple documents from the collection based on the provided filter expression.
 | |
|         /// </summary>
 | |
|         /// <param name="filterExpression">A lambda expression that defines the filter criteria for the documents to delete.</param>
 | |
|         public void DeleteMany(Expression<Func<TDocument, bool>> filterExpression)
 | |
|         {
 | |
|             _collection.DeleteMany(filterExpression);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Asynchronously deletes multiple documents from the collection based on the provided filter expression.
 | |
|         /// </summary>
 | |
|         /// <param name="filterExpression">A lambda expression that defines the filter criteria for the documents to delete.</param>
 | |
|         /// <returns>A task that represents the asynchronous operation.</returns>
 | |
|         public Task DeleteManyAsync(Expression<Func<TDocument, bool>> filterExpression)
 | |
|         {
 | |
|             return Task.Run(() => _collection.DeleteManyAsync(filterExpression));
 | |
|         }
 | |
|     }
 | |
| }
 | 
