Skip to content

Repository files navigation

MongoDB.DataAccess

It's a modern and generic data access structure for .NET and MongoDB. It supports UnitOfWork, Repository and QueryBuilder patterns. It also includes DbContext, IdGenerators and transactions support with replica set.

Give a Star! ⭐

If you like or are using this project to learn or start your solution, please give it a star. Thanks!

Status

build-and-publish Workflow Status

PackageNuGet
MongoDB.Data.Infrastructure.AbstractionsNugetNuget
MongoDB.Data.QueryBuilder.AbstractionsNugetNuget
MongoDB.Data.Repository.AbstractionsNugetNuget
MongoDB.Data.UnitOfWork.AbstractionsNugetNuget
--------------
MongoDB.Data.GeneratorsNugetNuget
MongoDB.Data.InfrastructureNugetNuget
MongoDB.Data.QueryBuilderNugetNuget
MongoDB.Data.RepositoryNugetNuget
MongoDB.Data.UnitOfWorkNugetNuget

Installation

MongoDB.DataAccess is available on Nuget.

Install-Package MongoDB.Data.Infrastructure.Abstractions -Version 1.8.5
Install-Package MongoDB.Data.QueryBuilder.Abstractions -Version 1.8.5
Install-Package MongoDB.Data.Repository.Abstractions -Version 1.8.5
Install-Package MongoDB.Data.UnitOfWork.Abstractions -Version 1.8.5
Install-Package MongoDB.Data.Generators -Version 1.8.5
Install-Package MongoDB.Data.Infrastructure -Version 1.8.5
Install-Package MongoDB.Data.QueryBuilder -Version 1.8.5
Install-Package MongoDB.Data.Repository -Version 1.8.5
Install-Package MongoDB.Data.UnitOfWork -Version 1.8.5

P.S.: MongoDB.Data.UnitOfWork depends on the other packages, so installing this package is enough.

Usage

The following code demonstrates basic usage of UnitOfWork, Repository and QueryBuilder patterns.

First of all, please register the dependencies into the MS Built-In container:

publicclassBloggingContext:MongoDbContext{publicBloggingContext(IMongoClientclient,IMongoDatabasedatabase,IMongoDbContextOptionsoptions):base(client,database,options){}}// Register the DbContextservices.AddMongoDbContext<IMongoDbContext,BloggingContext>(connectionString:Configuration.GetValue<string>("MongoSettings:Blogging:ConnectionString"),databaseName:Configuration.GetValue<string>("MongoSettings:Blogging:DatabaseName"),setupFluentConfigurationOptions: options =>options.ScanningAssemblies=new[]{typeof(BloggingContext).Assembly});// Register the UnitOfWorkservices.AddMongoDbUnitOfWork<BloggingContext>();

For multiple databases:

publicclassBloggingContext:MongoDbContext{publicBloggingContext(IMongoClientclient,IMongoDatabasedatabase,IMongoDbContextOptionsoptions):base(client,database,options){}}publicclassAccountingContext:MongoDbContext{publicAccountingContext(IMongoClientclient,IMongoDatabasedatabase,IMongoDbContextOptionsoptions):base(client,database,options){}}// Register the DbContextsservices.AddMongoDbContext<IMongoDbContext,BloggingContext>(connectionString:Configuration.GetValue<string>("MongoSettings:Blogging:ConnectionString"),databaseName:Configuration.GetValue<string>("MongoSettings:Blogging:DatabaseName"),setupFluentConfigurationOptions: options =>options.ScanningAssemblies=new[]{typeof(BloggingContext).Assembly});services.AddMongoDbContext<IMongoDbContext,AccountingContext>(connectionString:Configuration.GetValue<string>("MongoSettings:Accounting:ConnectionString"),databaseName:Configuration.GetValue<string>("MongoSettings:Accounting:DatabaseName"),setupFluentConfigurationOptions: options =>options.ScanningAssemblies=new[]{typeof(AccountingContext).Assembly});// Register the UnitOfWorkservices.AddMongoDbUnitOfWork<BloggingContext>();services.AddMongoDbUnitOfWork<AccountingContext>();

For multi-tenancy:

P.S: There are many approaches to implementing multi-tenancy in applications (Discriminator, Database per tenant, Schema per tenant...) and this one is just an example.

publicclassBloggingContext:MongoDbContext{publicBloggingContext(IMongoClientclient,IMongoDatabasedatabase,IMongoDbContextOptionsoptions):base(client,database,options){}}// Register the DbContextsservices.AddMongoDbContext<IMongoDbContext,BloggingContext>(connectionString:Configuration.GetValue<string>("MongoSettings:Blogging:TenantA:ConnectionString"),databaseName:Configuration.GetValue<string>("MongoSettings:Blogging:TenantA:DatabaseName"),setupDbContextOptions: options =>options.DbContextId=$"{nameof(BloggingContext)} - TenantA",setupFluentConfigurationOptions: options =>options.ScanningAssemblies=new[]{typeof(BloggingContext).Assembly});services.AddMongoDbContext<IMongoDbContext,BloggingContext>(connectionString:Configuration.GetValue<string>("MongoSettings:Blogging:TenantB:ConnectionString"),databaseName:Configuration.GetValue<string>("MongoSettings:Blogging:TenantB:DatabaseName"),setupDbContextOptions: options =>options.DbContextId=$"{nameof(BloggingContext)} - TenantB",setupFluentConfigurationOptions: options =>options.ScanningAssemblies=new[]{typeof(BloggingContext).Assembly});// Register the UnitOfWorkservices.AddMongoDbUnitOfWork<BloggingContext>();// Orservices.AddMongoDbUnitOfWork<BloggingContext>("BloggingContext - TenantA");services.AddMongoDbUnitOfWork<BloggingContext>("BloggingContext - TenantB");

After that, use the structure in your code like that:

privatereadonlyIMongoDbUnitOfWork<BloggingContext>_unitOfWork;// InjectionpublicBlogsController(IMongoDbUnitOfWork<BloggingContext> unitOfWork)=> _unitOfWork =unitOfWork??thrownewArgumentNullException(nameof(unitOfWork),$"{nameof(unitOfWork)} cannot be null.");// Or// Factory for multi-tenancypublicBlogsController(IMongoDbUnitOfWorkFactory<BloggingContext> unitOfWorkFactory,ITenantProvider tenantProvider){if(unitOfWorkFactoryisnull){thrownewArgumentNullException(nameof(unitOfWorkFactory),$"{nameof(unitOfWorkFactory)} cannot be null.");}if(tenantProviderisnull){thrownewArgumentNullException(nameof(tenantProvider),$"{nameof(tenantProvider)} cannot be null.");}vartenantId=tenantProvider.GetTenantId();_unitOfWork=unitOfWorkFactory.Create(tenantId);}// Or// If the TenantId is known and constantpublicBlogsController([FromKeyedServices("BloggingContext - TenantA")]IMongoDbUnitOfWork<BloggingContext> unitOfWork)=>_unitOfWork=unitOfWork??thrownewArgumentNullException(nameof(unitOfWork),$"{nameof(unitOfWork)} cannot be null.");publicvoidGetAllBlogs(){varrepository=_unitOfWork.Repository<Blog>();varquery=repository.MultipleResultQuery();varblogs=repository.Search(query);}publicvoidGetAllBlogsProjection(){varrepository=_unitOfWork.Repository<Blog>();varquery=repository.MultipleResultQuery().Select(selector =>new{Name=selector.Title,Link=selector.Url,Type=selector.Type.Description});varblogs=repository.Search(query);}publicvoidGetAllOrderedBlogs(){varrepository=_unitOfWork.Repository<Blog>();IMongoDbQuery<Blog>query;IList<Blog>blogs;query=repository.MultipleResultQuery().OrderByDescending("Id");blogs=repository.Search(query);query=repository.MultipleResultQuery().OrderByDescending(blog =>blog.Id);blogs=repository.Search(query);}publicvoidGetTopBlogs(){varrepository=_unitOfWork.Repository<Blog>();varquery=repository.MultipleResultQuery().Top(10);varblogs=repository.Search(query);}publicvoidGetPagedBlogs(){varrepository=_unitOfWork.Repository<Blog>();varquery=repository.MultipleResultQuery().Page(1,20);varblogs=repository.Search(query);}publicvoidGetBlogsPagedList(){varrepository=_unitOfWork.Repository<Blog>();varquery=repository.MultipleResultQuery().Page(1,20);varblogs=repository.Search(query).ToPagedList(query.Paging.PageIndex,query.Paging.PageSize,query.Paging.TotalCount);}publicvoidGetFilteredBlogs(){varrepository=_unitOfWork.Repository<Blog>();varquery=repository.MultipleResultQuery().AndFilter(blog =>blog.Url.StartsWith("/a/")).AndFilter(blog =>blog.Title.StartsWith("a")).AndFilter(blog =>blog.Posts.Any());varblogs=repository.Search(query);}publicvoidGetUrls(){varrepository=_unitOfWork.CustomRepository<ICustomBlogRepository>();varurls=repository.GetAllBlogUrls();}publicvoidGetBlogByUrl(){varrepository=_unitOfWork.Repository<Blog>();varquery=repository.SingleResultQuery().AndFilter(blog =>blog.Url.StartsWith("/a/")).OrderByDescending(blog =>blog.Id);varblogResult=repository.FirstOrDefault(query);}publicvoidGetBlogById(){varrepository=_unitOfWork.Repository<Blog>();varquery=repository.SingleResultQuery().AndFilter(blog =>blog.Id==1);varblogResult=repository.SingleOrDefault(query);}publicvoidGetBlogByIdProjection(){varrepository=_unitOfWork.Repository<Blog>();varquery=repository.SingleResultQuery().AndFilter(blog =>blog.Id==1).Select(selector =>new{selector.Id,Name=selector.Title,Link=selector.Url,Type=selector.Type.Description});varblogResult=repository.SingleOrDefault(query);}publicvoidExistsBlog(){varrepository=_unitOfWork.Repository<Blog>();varexists=repository.Any(blog =>blog.Url.StartsWith("/a/"));}publicvoidGetBlogCount(){varrepository=_unitOfWork.Repository<Blog>();varcount=repository.Count();varlongCount=repository.LongCount();}publicvoidMaxBlogId(){varrepository=_unitOfWork.Repository<Blog>();varid=repository.Max(blog =>blog.Id);}publicvoidMinBlogId(){varrepository=_unitOfWork.Repository<Blog>();varid=repository.Min(blog =>blog.Id);}publicvoidAddBlog(){varrepository=_unitOfWork.Repository<Blog>();repository.InsertOne(Seeder.SeedBlog(51));_unitOfWork.SaveChanges();}publicvoidUpdateBlog(){varrepository=_unitOfWork.Repository<Blog>();repository.ReplaceOne(x =>x.Id==id,model);_unitOfWork.SaveChanges();}publicvoidDeleteBlog(){varrepository=_unitOfWork.Repository<Blog>();repository.DeleteOne(x =>x.Id==id);_unitOfWork.SaveChanges();}publicvoidUpdateManyBlogs(){varrepository=_unitOfWork.Repository<Blog>();repository.UpdateMany(
blog =>blogIds.Contains(blog.Id),newDictionary<Expression<Func<Blog,object>>,object>{{ blog =>blog.Title,"updated-title"}});_unitOfWork.SaveChanges();}publicvoidBulkWriteBlogs(){varrepository=_unitOfWork.Repository<Blog>();varrequests=newList<WriteModel<Blog>>();foreach(varblogIdinblogIds){varfilter=Builders<Blog>.Filter.Eq(blog =>blog.Id,blogId);vardefinition=Builders<Blog>.Update.Set(blog =>blog.Title,$"a{blogId}-updated-title");requests.Add(newUpdateOneModel<Blog>(filter,definition));}repository.BulkWrite(requests);_unitOfWork.SaveChanges();}

The operations above are also available as async.

Please check some available samples here

Support / Contributing

If you want to help with the project, feel free to open pull requests and submit issues.

Donate

If you would like to show your support for this project, then please feel free to buy me a coffee.

Buy Me A Coffee

About

It's a modern and generic data access structure for .NET and MongoDB. It supports UnitOfWork, Repository and QueryBuilder patterns. It also includes DbContext, IdGenerators and transactions support with replica set.

Resources

Stars

44 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages