diff --git a/MongoDbGenericRepository/BaseMongoDbRepository.cs b/MongoDbGenericRepository/BaseMongoDbRepository.cs index 48ed66f..c3b1517 100644 --- a/MongoDbGenericRepository/BaseMongoDbRepository.cs +++ b/MongoDbGenericRepository/BaseMongoDbRepository.cs @@ -5,888 +5,24 @@ using System.Threading.Tasks; using System.Linq.Expressions; using MongoDbGenericRepository.Models; using System.Linq; +using MongoDbGenericRepository.Utils; namespace MongoDbGenericRepository { - /// - /// The IBaseMongoRepository exposes the functionality of the BaseMongoRepository. - /// - public interface IBaseMongoRepository - { - /// - /// The connection string. - /// - string ConnectionString { get; set; } - /// - /// The database name. - /// - string DatabaseName { get; set; } - - #region Create - - /// - /// Asynchronously adds a document to the collection. - /// - /// The type representing a Document. - /// The document you want to add. - Task AddOneAsync(TDocument document) where TDocument : IDocument; - - /// - /// Adds a document to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The document you want to add. - void AddOne(TDocument document) where TDocument : IDocument; - - /// - /// Asynchronously adds a list of documents to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The document you want to add. - Task AddManyAsync(IEnumerable documents) where TDocument : IDocument; - - /// - /// Adds a list of documents to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The document you want to add. - void AddMany(IEnumerable documents) where TDocument : IDocument; - - #endregion - - #region Create TKey - - /// - /// Asynchronously adds a document to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The document you want to add. - Task AddOneAsync(TDocument document) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Adds a document to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The document you want to add. - void AddOne(TDocument document) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Asynchronously adds a list of documents to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The documents you want to add. - Task AddManyAsync(IEnumerable documents) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Adds a list of documents to the collection. - /// Populates the Id and AddedAtUtc fields if necessary. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The documents you want to add. - void AddMany(IEnumerable documents) - where TDocument : IDocument - where TKey : IEquatable; - - #endregion - - #region Read - - /// - /// Asynchronously returns one document given its id. - /// - /// The type representing a Document. - /// The Id of the document you want to get. - /// An optional partition key. - Task GetByIdAsync(Guid id, string partitionKey = null) where TDocument : IDocument; - - /// - /// Returns one document given its id. - /// - /// The type representing a Document. - /// The Id of the document you want to get. - /// An optional partition key. - TDocument GetById(Guid id, string partitionKey = null) where TDocument : IDocument; - - /// - /// Asynchronously returns one document given an expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - Task GetOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Returns one document given an expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - TDocument GetOne(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Returns a collection cursor. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - IFindFluent GetCursor(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Asynchronously returns true if any of the document of the collection matches the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - Task AnyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Returns true if any of the document of the collection matches the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - bool Any(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Asynchronously returns a list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - Task> GetAllAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Returns a list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - List GetAll(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Asynchronously counts how many documents match the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - Task CountAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Counts how many documents match the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - long Count(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - #endregion - - #region Read TKey - - /// - /// Asynchronously returns one document given its id. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The Id of the document you want to get. - /// An optional partition key. - Task GetByIdAsync(TKey id, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Returns one document given its id. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The Id of the document you want to get. - /// An optional partition key. - TDocument GetById(TKey id, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Asynchronously returns one document given an expression filter. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - Task GetOneAsync(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Returns one document given an expression filter. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - TDocument GetOne(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - - /// - /// Returns a collection cursor. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - IFindFluent GetCursor(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - - /// - /// Returns true if any of the document of the collection matches the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - Task AnyAsync(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Returns true if any of the document of the collection matches the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - bool Any(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Asynchronously returns a list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - Task> GetAllAsync(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Returns a list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - List GetAll(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Asynchronously counts how many documents match the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partitionKey - Task CountAsync(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Counts how many documents match the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partitionKey - long Count(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - #endregion - - #region Update - - /// - /// Asynchronously Updates a document. - /// - /// The type representing a Document. - /// The document with the modifications you want to persist. - Task UpdateOneAsync(TDocument modifiedDocument) where TDocument : IDocument; - - /// - /// Updates a document. - /// - /// The type representing a Document. - /// The document with the modifications you want to persist. - bool UpdateOne(TDocument modifiedDocument) where TDocument : IDocument; - - /// - /// Updates the property field with the given value update a property field in entities. - /// - /// The type representing a Document. - /// The type of the field. - /// The document filter. - /// The field selector. - /// The new value of the property field. - bool UpdateOne(FilterDefinition filter, Expression> field, TField value, string partitionKey = null) - where TDocument : IDocument; - - /// - /// Updates the property field with the given value update a property field in entities. - /// - /// The type representing a Document. - /// The type of the field. - /// The document filter. - /// The field selector. - /// The new value of the property field. - Task UpdateOneAsync(FilterDefinition filter, Expression> field, TField value, string partitionKey = null) - where TDocument : IDocument; - - /// - /// Updates the property field with the given value update a property field in entities. - /// - /// The type representing a Document. - /// The type of the field. - /// The document you want to modify. - /// The field selector. - /// The new value of the property field. - bool UpdateOne(TDocument documentToModify, Expression> field, TField value) - where TDocument : IDocument; - - /// - /// Updates the property field with the given value update a property field in entities. - /// - /// The type representing a Document. - /// The type of the field. - /// The document you want to modify. - /// The field selector. - /// The new value of the property field. - Task UpdateOneAsync(TDocument documentToModify, Expression> field, TField value) - where TDocument : IDocument; - - /// - /// Takes a document you want to modify and applies the update you have defined in MongoDb. - /// - /// The type representing a Document. - /// The document you want to modify. - /// The update definition for the document. - Task UpdateOneAsync(TDocument documentToModify, UpdateDefinition update) - where TDocument : IDocument; - - /// - /// Takes a document you want to modify and applies the update you have defined in MongoDb. - /// - /// The type representing a Document. - /// The document you want to modify. - /// The update definition for the document. - bool UpdateOne(TDocument documentToModify, UpdateDefinition update) - where TDocument : IDocument; - - #endregion - - #region Update TKey - - /// - /// Asynchronously Updates a document. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The document with the modifications you want to persist. - Task UpdateOneAsync(TDocument modifiedDocument) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Updates a document. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The document with the modifications you want to persist. - bool UpdateOne(TDocument modifiedDocument) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Takes a document you want to modify and applies the update you have defined in MongoDb. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The document you want to modify. - /// The update definition for the document. - Task UpdateOneAsync(TDocument documentToModify, UpdateDefinition update) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Takes a document you want to modify and applies the update you have defined in MongoDb. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The document you want to modify. - /// The update definition for the document. - bool UpdateOne(TDocument documentToModify, UpdateDefinition update) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Updates the property field with the given value update a property field in entities. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type of the field. - /// The document you want to modify. - /// The field selector. - /// The new value of the property field. - Task UpdateOneAsync(TDocument documentToModify, Expression> field, TField value) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Updates the property field with the given value update a property field in entities. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type of the field. - /// The document you want to modify. - /// The field selector. - /// The new value of the property field. - bool UpdateOne(TDocument documentToModify, Expression> field, TField value) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Updates the property field with the given value update a property field in entities. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type of the field. - /// The document filter. - /// The field selector. - /// The new value of the property field. - Task UpdateOneAsync(FilterDefinition filter, Expression> field, TField value, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Updates the property field with the given value update a property field in entities. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type of the field. - /// The document filter. - /// The field selector. - /// The new value of the property field. - bool UpdateOne(FilterDefinition filter, Expression> field, TField value, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - #endregion - - #region Delete - - /// - /// Asynchronously deletes a document. - /// - /// The type representing a Document. - /// The document you want to delete. - /// The number of documents deleted. - Task DeleteOneAsync(TDocument document) where TDocument : IDocument; - - /// - /// Asynchronously deletes a document matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - Task DeleteOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Deletes a document. - /// - /// The type representing a Document. - /// The document you want to delete. - /// The number of documents deleted. - long DeleteOne(TDocument document) where TDocument : IDocument; - - /// - /// Deletes a document matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - long DeleteOne(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Asynchronously deletes the documents matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - Task DeleteManyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - /// - /// Asynchronously deletes a list of documents. - /// - /// The type representing a Document. - /// The list of documents to delete. - /// The number of documents deleted. - Task DeleteManyAsync(IEnumerable documents) where TDocument : IDocument; - - /// - /// Deletes a list of documents. - /// - /// The type representing a Document. - /// The list of documents to delete. - /// The number of documents deleted. - long DeleteMany(IEnumerable documents) where TDocument : IDocument; - - /// - /// Deletes the documents matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - long DeleteMany(Expression> filter, string partitionKey = null) where TDocument : IDocument; - - #endregion - - #region Delete TKey - - /// - /// Deletes a document. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The document you want to delete. - /// The number of documents deleted. - long DeleteOne(TDocument document) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Asynchronously deletes a document matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The document you want to delete. - /// The number of documents deleted. - Task DeleteOneAsync(TDocument document) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Deletes a document matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - long DeleteOne(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Asynchronously deletes a document matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - Task DeleteOneAsync(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Asynchronously deletes the documents matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - Task DeleteManyAsync(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Asynchronously deletes a list of documents. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The list of documents to delete. - /// The number of documents deleted. - Task DeleteManyAsync(IEnumerable documents) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Deletes a list of documents. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The list of documents to delete. - /// The number of documents deleted. - long DeleteMany(IEnumerable documents) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// Deletes the documents matching the condition of the LINQ expression filter. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - /// The number of documents deleted. - long DeleteMany(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - #endregion - - #region Project - - /// - /// Asynchronously returns a projected document matching the filter condition. - /// - /// The type representing a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TProjection : class; - - /// - /// Asynchronously returns a projected document matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - where TProjection : class; - - /// - /// Returns a projected document matching the filter condition. - /// - /// The type representing a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TProjection : class; - - /// - /// Returns a projected document matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - where TProjection : class; - - /// - /// Asynchronously returns a list of projected documents matching the filter condition. - /// - /// The type representing a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TProjection : class; - - /// - /// Asynchronously returns a list of projected documents matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - where TProjection : class; - - /// - /// Asynchronously returns a list of projected documents matching the filter condition. - /// - /// The type representing a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TProjection : class; - - /// - /// Asynchronously returns a list of projected documents matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The type representing the model you want to project to. - /// - /// The projection expression. - /// An optional partition key. - List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - where TProjection : class; - - #endregion - - /// - /// Asynchronously returns a paginated list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// - /// The number of documents you want to skip. Default value is 0. - /// The number of documents you want to take. Default value is 50. - /// An optional partition key. - Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) - where TDocument : IDocument; - - /// - /// Asynchronously returns a paginated list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// - /// The number of documents you want to skip. Default value is 0. - /// The number of documents you want to take. Default value is 50. - /// An optional partition key. - Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable; - - /// - /// GetAndUpdateOne with filter - /// - /// The type representing a Document. - /// - /// - /// - /// - Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) - where TDocument : IDocument; - - /// - /// GetAndUpdateOne with filter - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// - /// - /// - /// - Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) - where TDocument : IDocument - where TKey : IEquatable; - - #region Grouping - - /// - /// Groups a collection of documents given a grouping criteria, - /// and returns a list of projected documents. - /// - /// The type representing a Document. - /// The type of the grouping criteria. - /// The type of the projected group. - /// The grouping criteria. - /// The projected group result. - /// The partition key of your document, if any. - List GroupBy( - Expression> groupingCriteria, - Expression, TProjection>> groupProjection, - string partitionKey = null) - where TDocument : IDocument - where TProjection : class, new(); - - /// Groups filtered a collection of documents given a grouping criteria, - /// and returns a dictionary of listed document groups with keys having the different values of the grouping criteria. - /// - /// The type representing a Document. - /// The type of the grouping criteria. - /// The type of the projected group. - /// The grouping criteria. - /// The projected group result. - /// The partition key of your document, if any. - /// - List GroupBy(Expression> filter, - Expression> selector, - Expression, TProjection>> projection, - string partitionKey = null) - where TDocument : IDocument - where TProjection : class, new(); - - #endregion - } - /// /// The base Repository, it is meant to be inherited from by your custom custom MongoRepository implementation. /// Its constructor must be given a connection string and a database name. /// - public abstract class BaseMongoRepository : IBaseMongoRepository + public abstract class BaseMongoRepository : ReadOnlyMongoRepository, IBaseMongoRepository { - /// - /// The connection string. - /// - public string ConnectionString { get; set; } - - /// - /// The database name. - /// - public string DatabaseName { get; set; } + private static readonly Random Random = new Random(); /// /// The constructor taking a connection string and a database name. /// /// The connection string of the MongoDb server. /// The name of the database against which you want to perform operations. - protected BaseMongoRepository(string connectionString, string databaseName) + protected BaseMongoRepository(string connectionString, string databaseName) : base(connectionString, databaseName) { MongoDbContext = new MongoDbContext(connectionString, databaseName); } @@ -895,7 +31,7 @@ namespace MongoDbGenericRepository /// The contructor taking a . /// /// A mongodb context implementing - protected BaseMongoRepository(IMongoDbContext mongoDbContext) + protected BaseMongoRepository(IMongoDbContext mongoDbContext) : base(mongoDbContext) { MongoDbContext = mongoDbContext; } @@ -904,7 +40,7 @@ namespace MongoDbGenericRepository /// The contructor taking a . /// /// A mongodb context implementing - protected BaseMongoRepository(IMongoDatabase mongoDatabase) + protected BaseMongoRepository(IMongoDatabase mongoDatabase) : base(mongoDatabase) { MongoDbContext = new MongoDbContext(mongoDatabase); } @@ -1059,297 +195,6 @@ namespace MongoDbGenericRepository #endregion - #region Read - - /// - /// Asynchronously returns one document given its id. - /// - /// The type representing a Document. - /// The Id of the document you want to get. - /// An optional partition key. - public async Task GetByIdAsync(Guid id, string partitionKey = null) where TDocument : IDocument - { - var filter = Builders.Filter.Eq("Id", id); - return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); - } - - /// - /// Returns one document given its id. - /// - /// The type representing a Document. - /// The Id of the document you want to get. - /// An optional partition key. - public TDocument GetById(Guid id, string partitionKey = null) where TDocument : IDocument - { - var filter = Builders.Filter.Eq("Id", id); - return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); - } - - /// - /// Asynchronously returns one document given an expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public async Task GetOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); - } - - /// - /// Returns one document given an expression filter. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public TDocument GetOne(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); - } - - /// - /// Returns a collection cursor. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public IFindFluent GetCursor(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return HandlePartitioned(partitionKey).Find(filter); - } - - /// - /// Returns true if any of the document of the collection matches the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public async Task AnyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - var count = await HandlePartitioned(partitionKey).CountAsync(filter); - return (count > 0); - } - - /// - /// Returns true if any of the document of the collection matches the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public bool Any(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - var count = HandlePartitioned(partitionKey).Count(filter); - return (count > 0); - } - - /// - /// Asynchronously returns a list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public async Task> GetAllAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return await HandlePartitioned(partitionKey).Find(filter).ToListAsync(); - } - - /// - /// Returns a list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partition key. - public List GetAll(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return HandlePartitioned(partitionKey).Find(filter).ToList(); - } - - /// - /// Asynchronously counts how many documents match the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partitionKey - public async Task CountAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return await HandlePartitioned(partitionKey).CountAsync(filter); - } - - /// - /// Counts how many documents match the filter condition. - /// - /// The type representing a Document. - /// A LINQ expression filter. - /// An optional partitionKey - public long Count(Expression> filter, string partitionKey = null) where TDocument : IDocument - { - return HandlePartitioned(partitionKey).Find(filter).Count(); - } - - #endregion - - #region Read TKey - - /// - /// Asynchronously returns one document given its id. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The Id of the document you want to get. - /// An optional partition key. - public async Task GetByIdAsync(TKey id, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - { - var filter = Builders.Filter.Eq("Id", id); - return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); - } - - /// - /// Returns one document given its id. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// The Id of the document you want to get. - /// An optional partition key. - public TDocument GetById(TKey id, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - { - var filter = Builders.Filter.Eq("Id", id); - return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); - } - - /// - /// Asynchronously returns one document given an expression filter. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - public async Task GetOneAsync(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - { - return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); - } - - /// - /// Returns one document given an expression filter. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - public TDocument GetOne(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - { - return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); - } - - /// - /// Returns a collection cursor. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - public IFindFluent GetCursor(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - { - return HandlePartitioned(partitionKey).Find(filter); - } - - /// - /// Returns true if any of the document of the collection matches the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - public async Task AnyAsync(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - { - var count = await HandlePartitioned(partitionKey).CountAsync(filter); - return (count > 0); - } - - /// - /// Returns true if any of the document of the collection matches the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - public bool Any(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - { - var count = HandlePartitioned(partitionKey).Count(filter); - return (count > 0); - } - - /// - /// Asynchronously returns a list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - public async Task> GetAllAsync(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - { - return await HandlePartitioned(partitionKey).Find(filter).ToListAsync(); - } - - /// - /// Returns a list of the documents matching the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partition key. - public List GetAll(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - { - return HandlePartitioned(partitionKey).Find(filter).ToList(); - } - - /// - /// Asynchronously counts how many documents match the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partitionKey - public async Task CountAsync(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - { - return await HandlePartitioned(partitionKey).CountAsync(filter); - } - - /// - /// Counts how many documents match the filter condition. - /// - /// The type representing a Document. - /// The type of the primary key for a Document. - /// A LINQ expression filter. - /// An optional partitionKey - public long Count(Expression> filter, string partitionKey = null) - where TDocument : IDocument - where TKey : IEquatable - { - return HandlePartitioned(partitionKey).Find(filter).Count(); - } - - #endregion - #region Update /// @@ -2109,48 +954,55 @@ namespace MongoDbGenericRepository #endregion Find And Update - #region Private Methods - private IMongoCollection GetCollection(string partitionKey) where TDocument : IDocument + private TKey SetIdField() { - return MongoDbContext.GetCollection(partitionKey); - } - - private IMongoCollection GetCollection() where TDocument : IDocument - { - return MongoDbContext.GetCollection(); - } - - private IMongoCollection HandlePartitioned(TDocument document) where TDocument : IDocument - { - if (document is IPartitionedDocument) + var idTypeName = typeof(TKey).Name; + switch (idTypeName) { - return GetCollection(((IPartitionedDocument)document).PartitionKey); + case "Guid": + return (TKey)(object)Guid.NewGuid(); + case "Int16": + return (TKey)(object)Random.Next(1, short.MaxValue); + case "Int32": + return (TKey)(object)Random.Next(1, int.MaxValue); + case "Int64": + return (TKey)(object)(Random.NextLong(1, long.MaxValue)); + case "String": + return (TKey)(object)Guid.NewGuid().ToString(); } - return GetCollection(); + throw new ArgumentException($"{idTypeName} is not a supported Id type, the Id of the document cannot be set."); } - private IMongoCollection HandlePartitioned(TDocument document) + /// + /// Sets the value of the document Id if it is not set already. + /// + /// The document type. + /// The type of the primary key. + /// The document. + protected void FormatDocument(TDocument document) where TDocument : IDocument where TKey : IEquatable { - if (document is IPartitionedDocument) + if (document == null) { - return GetCollection(((IPartitionedDocument)document).PartitionKey); + throw new ArgumentNullException(nameof(document)); + } + var defaultTKey = default(TKey); + if (document.Id == null + || (defaultTKey != null + && defaultTKey.Equals(document.Id))) + { + document.Id = SetIdField(); } - return GetCollection(); } - private IMongoCollection HandlePartitioned(string partitionKey) where TDocument : IDocument - { - if (!string.IsNullOrEmpty(partitionKey)) - { - return GetCollection(partitionKey); - } - return GetCollection(); - } - - private void FormatDocument(TDocument document) where TDocument : IDocument + /// + /// Sets the value of the document Id if it is not set already. + /// + /// The document type. + /// The document. + protected void FormatDocument(TDocument document) where TDocument : IDocument { if (document == null) { @@ -2161,42 +1013,5 @@ namespace MongoDbGenericRepository document.Id = Guid.NewGuid(); } } - - private IMongoCollection GetCollection(string partitionKey) - where TDocument : IDocument - where TKey : IEquatable - { - return MongoDbContext.GetCollection(partitionKey); - } - - private IMongoCollection GetCollection() - where TDocument : IDocument - where TKey : IEquatable - { - return MongoDbContext.GetCollection(); - } - - private IMongoCollection HandlePartitioned(string partitionKey) - where TDocument : IDocument - where TKey : IEquatable - { - if (!string.IsNullOrEmpty(partitionKey)) - { - return GetCollection(partitionKey); - } - return GetCollection(); - } - - private void FormatDocument(TDocument document) - where TDocument : IDocument - where TKey : IEquatable - { - if (document == null) - { - throw new ArgumentNullException(nameof(document)); - } - } - - #endregion } } \ No newline at end of file diff --git a/MongoDbGenericRepository/IBaseMongoRepository.cs b/MongoDbGenericRepository/IBaseMongoRepository.cs new file mode 100644 index 0000000..80aea53 --- /dev/null +++ b/MongoDbGenericRepository/IBaseMongoRepository.cs @@ -0,0 +1,641 @@ +using MongoDB.Driver; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Linq.Expressions; +using MongoDbGenericRepository.Models; +using System.Linq; + +namespace MongoDbGenericRepository +{ + + /// + /// The IBaseMongoRepository exposes the CRUD functionality of the BaseMongoRepository. + /// + public interface IBaseMongoRepository : IReadOnlyMongoRepository + { + #region Create + + /// + /// Asynchronously adds a document to the collection. + /// + /// The type representing a Document. + /// The document you want to add. + Task AddOneAsync(TDocument document) where TDocument : IDocument; + + /// + /// Adds a document to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The document you want to add. + void AddOne(TDocument document) where TDocument : IDocument; + + /// + /// Asynchronously adds a list of documents to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The document you want to add. + Task AddManyAsync(IEnumerable documents) where TDocument : IDocument; + + /// + /// Adds a list of documents to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The document you want to add. + void AddMany(IEnumerable documents) where TDocument : IDocument; + + #endregion + + #region Create TKey + + /// + /// Asynchronously adds a document to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to add. + Task AddOneAsync(TDocument document) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Adds a document to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to add. + void AddOne(TDocument document) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Asynchronously adds a list of documents to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The documents you want to add. + Task AddManyAsync(IEnumerable documents) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Adds a list of documents to the collection. + /// Populates the Id and AddedAtUtc fields if necessary. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The documents you want to add. + void AddMany(IEnumerable documents) + where TDocument : IDocument + where TKey : IEquatable; + + #endregion + + #region Update + + /// + /// Asynchronously Updates a document. + /// + /// The type representing a Document. + /// The document with the modifications you want to persist. + Task UpdateOneAsync(TDocument modifiedDocument) where TDocument : IDocument; + + /// + /// Updates a document. + /// + /// The type representing a Document. + /// The document with the modifications you want to persist. + bool UpdateOne(TDocument modifiedDocument) where TDocument : IDocument; + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the field. + /// The document filter. + /// The field selector. + /// The new value of the property field. + bool UpdateOne(FilterDefinition filter, Expression> field, TField value, string partitionKey = null) + where TDocument : IDocument; + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the field. + /// The document filter. + /// The field selector. + /// The new value of the property field. + Task UpdateOneAsync(FilterDefinition filter, Expression> field, TField value, string partitionKey = null) + where TDocument : IDocument; + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the field. + /// The document you want to modify. + /// The field selector. + /// The new value of the property field. + bool UpdateOne(TDocument documentToModify, Expression> field, TField value) + where TDocument : IDocument; + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the field. + /// The document you want to modify. + /// The field selector. + /// The new value of the property field. + Task UpdateOneAsync(TDocument documentToModify, Expression> field, TField value) + where TDocument : IDocument; + + /// + /// Takes a document you want to modify and applies the update you have defined in MongoDb. + /// + /// The type representing a Document. + /// The document you want to modify. + /// The update definition for the document. + Task UpdateOneAsync(TDocument documentToModify, UpdateDefinition update) + where TDocument : IDocument; + + /// + /// Takes a document you want to modify and applies the update you have defined in MongoDb. + /// + /// The type representing a Document. + /// The document you want to modify. + /// The update definition for the document. + bool UpdateOne(TDocument documentToModify, UpdateDefinition update) + where TDocument : IDocument; + + #endregion + + #region Update TKey + + /// + /// Asynchronously Updates a document. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document with the modifications you want to persist. + Task UpdateOneAsync(TDocument modifiedDocument) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Updates a document. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document with the modifications you want to persist. + bool UpdateOne(TDocument modifiedDocument) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Takes a document you want to modify and applies the update you have defined in MongoDb. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to modify. + /// The update definition for the document. + Task UpdateOneAsync(TDocument documentToModify, UpdateDefinition update) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Takes a document you want to modify and applies the update you have defined in MongoDb. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to modify. + /// The update definition for the document. + bool UpdateOne(TDocument documentToModify, UpdateDefinition update) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type of the field. + /// The document you want to modify. + /// The field selector. + /// The new value of the property field. + Task UpdateOneAsync(TDocument documentToModify, Expression> field, TField value) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type of the field. + /// The document you want to modify. + /// The field selector. + /// The new value of the property field. + bool UpdateOne(TDocument documentToModify, Expression> field, TField value) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type of the field. + /// The document filter. + /// The field selector. + /// The new value of the property field. + Task UpdateOneAsync(FilterDefinition filter, Expression> field, TField value, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Updates the property field with the given value update a property field in entities. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type of the field. + /// The document filter. + /// The field selector. + /// The new value of the property field. + bool UpdateOne(FilterDefinition filter, Expression> field, TField value, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + #endregion + + #region Delete + + /// + /// Asynchronously deletes a document. + /// + /// The type representing a Document. + /// The document you want to delete. + /// The number of documents deleted. + Task DeleteOneAsync(TDocument document) where TDocument : IDocument; + + /// + /// Asynchronously deletes a document matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + Task DeleteOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Deletes a document. + /// + /// The type representing a Document. + /// The document you want to delete. + /// The number of documents deleted. + long DeleteOne(TDocument document) where TDocument : IDocument; + + /// + /// Deletes a document matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + long DeleteOne(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Asynchronously deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + Task DeleteManyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Asynchronously deletes a list of documents. + /// + /// The type representing a Document. + /// The list of documents to delete. + /// The number of documents deleted. + Task DeleteManyAsync(IEnumerable documents) where TDocument : IDocument; + + /// + /// Deletes a list of documents. + /// + /// The type representing a Document. + /// The list of documents to delete. + /// The number of documents deleted. + long DeleteMany(IEnumerable documents) where TDocument : IDocument; + + /// + /// Deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + long DeleteMany(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + #endregion + + #region Delete TKey + + /// + /// Deletes a document. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to delete. + /// The number of documents deleted. + long DeleteOne(TDocument document) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Asynchronously deletes a document matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The document you want to delete. + /// The number of documents deleted. + Task DeleteOneAsync(TDocument document) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Deletes a document matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + long DeleteOne(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Asynchronously deletes a document matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + Task DeleteOneAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Asynchronously deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + Task DeleteManyAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Asynchronously deletes a list of documents. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The list of documents to delete. + /// The number of documents deleted. + Task DeleteManyAsync(IEnumerable documents) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Deletes a list of documents. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The list of documents to delete. + /// The number of documents deleted. + long DeleteMany(IEnumerable documents) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Deletes the documents matching the condition of the LINQ expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + /// The number of documents deleted. + long DeleteMany(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + #endregion + + #region Project + + /// + /// Asynchronously returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class; + + /// + /// Asynchronously returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + Task ProjectOneAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class; + + /// + /// Returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class; + + /// + /// Returns a projected document matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + TProjection ProjectOne(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class; + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class; + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + Task> ProjectManyAsync(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class; + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TProjection : class; + + /// + /// Asynchronously returns a list of projected documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The type representing the model you want to project to. + /// + /// The projection expression. + /// An optional partition key. + List ProjectMany(Expression> filter, Expression> projection, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + where TProjection : class; + + #endregion + + /// + /// Asynchronously returns a paginated list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// + /// The number of documents you want to skip. Default value is 0. + /// The number of documents you want to take. Default value is 50. + /// An optional partition key. + Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) + where TDocument : IDocument; + + /// + /// Asynchronously returns a paginated list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// + /// The number of documents you want to skip. Default value is 0. + /// The number of documents you want to take. Default value is 50. + /// An optional partition key. + Task> GetPaginatedAsync(Expression> filter, int skipNumber = 0, int takeNumber = 50, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// GetAndUpdateOne with filter + /// + /// The type representing a Document. + /// + /// + /// + /// + Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) + where TDocument : IDocument; + + /// + /// GetAndUpdateOne with filter + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// + /// + /// + /// + Task GetAndUpdateOne(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options) + where TDocument : IDocument + where TKey : IEquatable; + + #region Grouping + + /// + /// Groups a collection of documents given a grouping criteria, + /// and returns a list of projected documents. + /// + /// The type representing a Document. + /// The type of the grouping criteria. + /// The type of the projected group. + /// The grouping criteria. + /// The projected group result. + /// The partition key of your document, if any. + List GroupBy( + Expression> groupingCriteria, + Expression, TProjection>> groupProjection, + string partitionKey = null) + where TDocument : IDocument + where TProjection : class, new(); + + /// Groups filtered a collection of documents given a grouping criteria, + /// and returns a dictionary of listed document groups with keys having the different values of the grouping criteria. + /// + /// The type representing a Document. + /// The type of the grouping criteria. + /// The type of the projected group. + /// The grouping criteria. + /// The projected group result. + /// The partition key of your document, if any. + /// + List GroupBy(Expression> filter, + Expression> selector, + Expression, TProjection>> projection, + string partitionKey = null) + where TDocument : IDocument + where TProjection : class, new(); + + #endregion + } + +} diff --git a/MongoDbGenericRepository/IReadOnlyMongoRepository.cs b/MongoDbGenericRepository/IReadOnlyMongoRepository.cs new file mode 100644 index 0000000..04036d1 --- /dev/null +++ b/MongoDbGenericRepository/IReadOnlyMongoRepository.cs @@ -0,0 +1,244 @@ +using MongoDB.Driver; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Linq.Expressions; +using MongoDbGenericRepository.Models; + +namespace MongoDbGenericRepository +{ + /// + /// The IReadOnlyMongoRepository exposes the readonly functionality of the BaseMongoRepository. + /// + public interface IReadOnlyMongoRepository + { + /// + /// The connection string. + /// + string ConnectionString { get; set; } + /// + /// The database name. + /// + string DatabaseName { get; set; } + + #region Read + + /// + /// Asynchronously returns one document given its id. + /// + /// The type representing a Document. + /// The Id of the document you want to get. + /// An optional partition key. + Task GetByIdAsync(Guid id, string partitionKey = null) where TDocument : IDocument; + + /// + /// Returns one document given its id. + /// + /// The type representing a Document. + /// The Id of the document you want to get. + /// An optional partition key. + TDocument GetById(Guid id, string partitionKey = null) where TDocument : IDocument; + + /// + /// Asynchronously returns one document given an expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + Task GetOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Returns one document given an expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + TDocument GetOne(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Returns a collection cursor. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + IFindFluent GetCursor(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Asynchronously returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + Task AnyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + bool Any(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Asynchronously returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + Task> GetAllAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + List GetAll(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Asynchronously counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + Task CountAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + /// + /// Counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + long Count(Expression> filter, string partitionKey = null) where TDocument : IDocument; + + #endregion + + #region Read TKey + + /// + /// Asynchronously returns one document given its id. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The Id of the document you want to get. + /// An optional partition key. + Task GetByIdAsync(TKey id, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Returns one document given its id. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The Id of the document you want to get. + /// An optional partition key. + TDocument GetById(TKey id, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Asynchronously returns one document given an expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + Task GetOneAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Returns one document given an expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + TDocument GetOne(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + + /// + /// Returns a collection cursor. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + IFindFluent GetCursor(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + + /// + /// Returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + Task AnyAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + bool Any(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Asynchronously returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + Task> GetAllAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + List GetAll(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Asynchronously counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partitionKey + Task CountAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + /// + /// Counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partitionKey + long Count(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable; + + #endregion + } + +} diff --git a/MongoDbGenericRepository/MongoDbContext.cs b/MongoDbGenericRepository/MongoDbContext.cs index f3854e9..fbfb93b 100644 --- a/MongoDbGenericRepository/MongoDbContext.cs +++ b/MongoDbGenericRepository/MongoDbContext.cs @@ -1,5 +1,6 @@ using MongoDB.Driver; using MongoDbGenericRepository.Models; +using MongoDbGenericRepository.Utils; using System; namespace MongoDbGenericRepository diff --git a/MongoDbGenericRepository/ReadOnlyMongoRepository.cs b/MongoDbGenericRepository/ReadOnlyMongoRepository.cs new file mode 100644 index 0000000..41828b0 --- /dev/null +++ b/MongoDbGenericRepository/ReadOnlyMongoRepository.cs @@ -0,0 +1,469 @@ +using MongoDB.Driver; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Linq.Expressions; +using MongoDbGenericRepository.Models; +using System.Linq; + +namespace MongoDbGenericRepository +{ + /// + /// The ReadOnlyMongoRepository implements the readonly functionality of the IReadOnlyMongoRepository. + /// + public class ReadOnlyMongoRepository : IReadOnlyMongoRepository + { + /// + /// The connection string. + /// + public string ConnectionString { get; set; } + + /// + /// The database name. + /// + public string DatabaseName { get; set; } + + /// + /// The MongoDbContext + /// + protected IMongoDbContext MongoDbContext = null; + + /// + /// The constructor taking a connection string and a database name. + /// + /// The connection string of the MongoDb server. + /// The name of the database against which you want to perform operations. + protected ReadOnlyMongoRepository(string connectionString, string databaseName) + { + MongoDbContext = new MongoDbContext(connectionString, databaseName); + } + + /// + /// The contructor taking a . + /// + /// A mongodb context implementing + protected ReadOnlyMongoRepository(IMongoDbContext mongoDbContext) + { + MongoDbContext = mongoDbContext; + } + + /// + /// The contructor taking a . + /// + /// A mongodb context implementing + protected ReadOnlyMongoRepository(IMongoDatabase mongoDatabase) + { + MongoDbContext = new MongoDbContext(mongoDatabase); + } + + #region Read + + /// + /// Asynchronously returns one document given its id. + /// + /// The type representing a Document. + /// The Id of the document you want to get. + /// An optional partition key. + public async Task GetByIdAsync(Guid id, string partitionKey = null) where TDocument : IDocument + { + var filter = Builders.Filter.Eq("Id", id); + return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); + } + + /// + /// Returns one document given its id. + /// + /// The type representing a Document. + /// The Id of the document you want to get. + /// An optional partition key. + public TDocument GetById(Guid id, string partitionKey = null) where TDocument : IDocument + { + var filter = Builders.Filter.Eq("Id", id); + return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); + } + + /// + /// Asynchronously returns one document given an expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public async Task GetOneAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); + } + + /// + /// Returns one document given an expression filter. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public TDocument GetOne(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); + } + + /// + /// Returns a collection cursor. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public IFindFluent GetCursor(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return HandlePartitioned(partitionKey).Find(filter); + } + + /// + /// Returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public async Task AnyAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + var count = await HandlePartitioned(partitionKey).CountAsync(filter); + return (count > 0); + } + + /// + /// Returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public bool Any(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + var count = HandlePartitioned(partitionKey).Count(filter); + return (count > 0); + } + + /// + /// Asynchronously returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public async Task> GetAllAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return await HandlePartitioned(partitionKey).Find(filter).ToListAsync(); + } + + /// + /// Returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partition key. + public List GetAll(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return HandlePartitioned(partitionKey).Find(filter).ToList(); + } + + /// + /// Asynchronously counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partitionKey + public async Task CountAsync(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return await HandlePartitioned(partitionKey).CountAsync(filter); + } + + /// + /// Counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// A LINQ expression filter. + /// An optional partitionKey + public long Count(Expression> filter, string partitionKey = null) where TDocument : IDocument + { + return HandlePartitioned(partitionKey).Find(filter).Count(); + } + + #endregion + + #region Read TKey + + /// + /// Asynchronously returns one document given its id. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The Id of the document you want to get. + /// An optional partition key. + public async Task GetByIdAsync(TKey id, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + var filter = Builders.Filter.Eq("Id", id); + return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); + } + + /// + /// Returns one document given its id. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// The Id of the document you want to get. + /// An optional partition key. + public TDocument GetById(TKey id, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + var filter = Builders.Filter.Eq("Id", id); + return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); + } + + /// + /// Asynchronously returns one document given an expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public async Task GetOneAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(); + } + + /// + /// Returns one document given an expression filter. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public TDocument GetOne(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); + } + + /// + /// Returns a collection cursor. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public IFindFluent GetCursor(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + return HandlePartitioned(partitionKey).Find(filter); + } + + /// + /// Returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public async Task AnyAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + var count = await HandlePartitioned(partitionKey).CountAsync(filter); + return (count > 0); + } + + /// + /// Returns true if any of the document of the collection matches the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public bool Any(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + var count = HandlePartitioned(partitionKey).Count(filter); + return (count > 0); + } + + /// + /// Asynchronously returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public async Task> GetAllAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + return await HandlePartitioned(partitionKey).Find(filter).ToListAsync(); + } + + /// + /// Returns a list of the documents matching the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partition key. + public List GetAll(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + return HandlePartitioned(partitionKey).Find(filter).ToList(); + } + + /// + /// Asynchronously counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partitionKey + public async Task CountAsync(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + return await HandlePartitioned(partitionKey).CountAsync(filter); + } + + /// + /// Counts how many documents match the filter condition. + /// + /// The type representing a Document. + /// The type of the primary key for a Document. + /// A LINQ expression filter. + /// An optional partitionKey + public long Count(Expression> filter, string partitionKey = null) + where TDocument : IDocument + where TKey : IEquatable + { + return HandlePartitioned(partitionKey).Find(filter).Count(); + } + + #endregion + + #region Private Methods + + /// + /// Gets a collections for the type TDocument with the matching partition key. + /// + /// The document type. + /// The partion key. + /// An + protected IMongoCollection GetCollection(string partitionKey) where TDocument : IDocument + { + return MongoDbContext.GetCollection(partitionKey); + } + + /// + /// Gets a collections for the type TDocument + /// + /// The document type. + /// + protected IMongoCollection GetCollection() where TDocument : IDocument + { + return MongoDbContext.GetCollection(); + } + + /// + /// Gets a collections for the type TDocument + /// + /// The document type. + /// The document. + /// + protected IMongoCollection HandlePartitioned(TDocument document) where TDocument : IDocument + { + if (document is IPartitionedDocument) + { + return GetCollection(((IPartitionedDocument)document).PartitionKey); + } + return GetCollection(); + } + + /// + /// Gets a collections for a potentially partitioned document type. + /// + /// The document type. + /// The type of the primary key. + /// The document. + /// + protected IMongoCollection HandlePartitioned(TDocument document) + where TDocument : IDocument + where TKey : IEquatable + { + if (document is IPartitionedDocument) + { + return GetCollection(((IPartitionedDocument)document).PartitionKey); + } + return GetCollection(); + } + + /// + /// Gets a collections for a potentially partitioned document type. + /// + /// The document type. + /// The collection partition key. + /// + protected IMongoCollection HandlePartitioned(string partitionKey) where TDocument : IDocument + { + if (!string.IsNullOrEmpty(partitionKey)) + { + return GetCollection(partitionKey); + } + return GetCollection(); + } + + /// + /// Gets a collections for the type TDocument with a partition key. + /// + /// The document type. + /// The type of the primary key. + /// The collection partition key. + /// + protected IMongoCollection GetCollection(string partitionKey) + where TDocument : IDocument + where TKey : IEquatable + { + return MongoDbContext.GetCollection(partitionKey); + } + + /// + /// Gets a collections for the type TDocument + /// + /// The document type. + /// The type of the primary key. + /// + protected IMongoCollection GetCollection() + where TDocument : IDocument + where TKey : IEquatable + { + return MongoDbContext.GetCollection(); + } + + /// + /// Gets a collections for a potentially partitioned document type. + /// + /// The document type. + /// The type of the primary key. + /// The collection partition key. + /// + protected IMongoCollection HandlePartitioned(string partitionKey) + where TDocument : IDocument + where TKey : IEquatable + { + if (!string.IsNullOrEmpty(partitionKey)) + { + return GetCollection(partitionKey); + } + return GetCollection(); + } + + #endregion + + } +} diff --git a/MongoDbGenericRepository/Pluralization.cs b/MongoDbGenericRepository/Utils/Pluralization.cs similarity index 99% rename from MongoDbGenericRepository/Pluralization.cs rename to MongoDbGenericRepository/Utils/Pluralization.cs index 020be50..cca18b4 100644 --- a/MongoDbGenericRepository/Pluralization.cs +++ b/MongoDbGenericRepository/Utils/Pluralization.cs @@ -64,7 +64,7 @@ using System.Collections.Generic; using System.Text.RegularExpressions; using System.Threading; -namespace MongoDbGenericRepository +namespace MongoDbGenericRepository.Utils { /// /// Container for registered Vocabularies. At present, only a single vocabulary is supported: Default. diff --git a/MongoDbGenericRepository/Utils/RandomExtensions.cs b/MongoDbGenericRepository/Utils/RandomExtensions.cs new file mode 100644 index 0000000..97cd79a --- /dev/null +++ b/MongoDbGenericRepository/Utils/RandomExtensions.cs @@ -0,0 +1,60 @@ +using System; + +namespace MongoDbGenericRepository.Utils +{ + // Thanks BlueRaja - Danny Pflughoeft https://stackoverflow.com/a/13095144/5103354 + /// + /// Extensions for the random number generator + /// + public static class RandomExtensions + { + /// + /// Returns a random long from min (inclusive) to max (exclusive) + /// + /// The given random instance + /// The inclusive minimum bound + /// The exclusive maximum bound. Must be greater than min + public static long NextLong(this Random random, long min, long max) + { + if (max <= min) + throw new ArgumentOutOfRangeException("max", "max must be > min!"); + + //Working with ulong so that modulo works correctly with values > long.MaxValue + ulong uRange = (ulong)(max - min); + + //Prevent a modulo bias; see https://stackoverflow.com/a/10984975/238419 + //for more information. + //In the worst case, the expected number of calls is 2 (though usually it's + //much closer to 1) so this loop doesn't really hurt performance at all. + ulong ulongRand; + do + { + byte[] buf = new byte[8]; + random.NextBytes(buf); + ulongRand = (ulong)BitConverter.ToInt64(buf, 0); + } while (ulongRand > ulong.MaxValue - ((ulong.MaxValue % uRange) + 1) % uRange); + + return (long)(ulongRand % uRange) + min; + } + + /// + /// Returns a random long from 0 (inclusive) to max (exclusive) + /// + /// The given random instance + /// The exclusive maximum bound. Must be greater than 0 + public static long NextLong(this Random random, long max) + { + return random.NextLong(0, max); + } + + /// + /// Returns a random long over all possible values of long (except long.MaxValue, similar to + /// random.Next()) + /// + /// The given random instance + public static long NextLong(this Random random) + { + return random.NextLong(long.MinValue, long.MaxValue); + } + } +}