https://github.com/ffernandolima/mongo-db-data-access
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.
https://github.com/ffernandolima/mongo-db-data-access
Last synced: about 1 year ago
JSON representation
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.
- Host: GitHub
- URL: https://github.com/ffernandolima/mongo-db-data-access
- Owner: ffernandolima
- License: mit
- Created: 2021-12-15T23:33:21.000Z (over 4 years ago)
- Default Branch: main
- Last Pushed: 2024-11-26T12:44:54.000Z (over 1 year ago)
- Last Synced: 2025-03-29T04:05:17.096Z (about 1 year ago)
- Language: C#
- Homepage:
- Size: 231 KB
- Stars: 40
- Watchers: 3
- Forks: 6
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# 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! :star:
If you like or are using this project to learn or start your solution, please give it a star. Thanks!
## Status
[](https://github.com/ffernandolima/mongo-db-data-access/actions/workflows/build-and-publish.yml/branch=main)
| Package | NuGet |
| ------- | ------- |
| MongoDB.Data.Infrastructure.Abstractions | [ ](https://www.nuget.org/packages/MongoDB.Data.Infrastructure.Abstractions/1.8.1) |
| MongoDB.Data.QueryBuilder.Abstractions | [ ](https://www.nuget.org/packages/MongoDB.Data.QueryBuilder.Abstractions/1.8.1) |
| MongoDB.Data.Repository.Abstractions | [ ](https://www.nuget.org/packages/MongoDB.Data.Repository.Abstractions/1.8.1) |
| MongoDB.Data.UnitOfWork.Abstractions | [ ](https://www.nuget.org/packages/MongoDB.Data.UnitOfWork.Abstractions/1.8.1) |
| ------- | ------- |
| MongoDB.Data.Generators | [ ](https://www.nuget.org/packages/MongoDB.Data.Generators/1.8.1) |
| MongoDB.Data.Infrastructure | [ ](https://www.nuget.org/packages/MongoDB.Data.Infrastructure/1.8.1) |
| MongoDB.Data.QueryBuilder | [ ](https://www.nuget.org/packages/MongoDB.Data.QueryBuilder/1.8.1) |
| MongoDB.Data.Repository | [ ](https://www.nuget.org/packages/MongoDB.Data.Repository/1.8.1) |
| MongoDB.Data.UnitOfWork | [ ](https://www.nuget.org/packages/MongoDB.Data.UnitOfWork/1.8.1) |
## Installation
MongoDB.DataAccess is available on Nuget.
```
Install-Package MongoDB.Data.Infrastructure.Abstractions -Version 1.8.1
Install-Package MongoDB.Data.QueryBuilder.Abstractions -Version 1.8.1
Install-Package MongoDB.Data.Repository.Abstractions -Version 1.8.1
Install-Package MongoDB.Data.UnitOfWork.Abstractions -Version 1.8.1
Install-Package MongoDB.Data.Generators -Version 1.8.1
Install-Package MongoDB.Data.Infrastructure -Version 1.8.1
Install-Package MongoDB.Data.QueryBuilder -Version 1.8.1
Install-Package MongoDB.Data.Repository -Version 1.8.1
Install-Package MongoDB.Data.UnitOfWork -Version 1.8.1
```
**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:
```C#
public class BloggingContext : MongoDbContext
{
public BloggingContext(IMongoClient client, IMongoDatabase database, IMongoDbContextOptions options)
: base(client, database, options)
{ }
}
// Register the DbContext
services.AddMongoDbContext(
connectionString: Configuration.GetValue("MongoSettings:Blogging:ConnectionString"),
databaseName: Configuration.GetValue("MongoSettings:Blogging:DatabaseName"),
setupFluentConfigurationOptions: options => options.ScanningAssemblies = new[] { typeof(BloggingContext).Assembly });
// Register the UnitOfWork
services.AddMongoDbUnitOfWork();
```
For multiple databases:
```C#
public class BloggingContext : MongoDbContext
{
public BloggingContext(IMongoClient client, IMongoDatabase database, IMongoDbContextOptions options)
: base(client, database, options)
{ }
}
public class AccountingContext : MongoDbContext
{
public AccountingContext(IMongoClient client, IMongoDatabase database, IMongoDbContextOptions options)
: base(client, database, options)
{ }
}
// Register the DbContexts
services.AddMongoDbContext(
connectionString: Configuration.GetValue("MongoSettings:Blogging:ConnectionString"),
databaseName: Configuration.GetValue("MongoSettings:Blogging:DatabaseName"),
setupFluentConfigurationOptions: options => options.ScanningAssemblies = new[] { typeof(BloggingContext).Assembly });
services.AddMongoDbContext(
connectionString: Configuration.GetValue("MongoSettings:Accounting:ConnectionString"),
databaseName: Configuration.GetValue("MongoSettings:Accounting:DatabaseName"),
setupFluentConfigurationOptions: options => options.ScanningAssemblies = new[] { typeof(AccountingContext).Assembly });
// Register the UnitOfWork
services.AddMongoDbUnitOfWork();
services.AddMongoDbUnitOfWork();
```
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.
```C#
public class BloggingContext : MongoDbContext
{
public BloggingContext(IMongoClient client, IMongoDatabase database, IMongoDbContextOptions options)
: base(client, database, options)
{ }
}
// Register the DbContexts
services.AddMongoDbContext(
connectionString: Configuration.GetValue("MongoSettings:Blogging:TenantA:ConnectionString"),
databaseName: Configuration.GetValue("MongoSettings:Blogging:TenantA:DatabaseName"),
setupDbContextOptions: options => options.DbContextId = $"{nameof(BloggingContext)} - TenantA",
setupFluentConfigurationOptions: options => options.ScanningAssemblies = new[] { typeof(BloggingContext).Assembly });
services.AddMongoDbContext(
connectionString: Configuration.GetValue("MongoSettings:Blogging:TenantB:ConnectionString"),
databaseName: Configuration.GetValue("MongoSettings:Blogging:TenantB:DatabaseName"),
setupDbContextOptions: options => options.DbContextId = $"{nameof(BloggingContext)} - TenantB",
setupFluentConfigurationOptions: options => options.ScanningAssemblies = new[] { typeof(BloggingContext).Assembly });
// Register the UnitOfWork
services.AddMongoDbUnitOfWork();
```
After that, use the structure in your code like that:
```C#
private readonly IMongoDbUnitOfWork _unitOfWork;
// Injection
public BlogsController(IMongoDbUnitOfWork unitOfWork)
=> _unitOfWork = unitOfWork ?? throw new ArgumentNullException(nameof(unitOfWork), $"{nameof(unitOfWork)} cannot be null.");
// Or
// Factory for multi-tenancy
public BlogsController(IMongoDbUnitOfWorkFactory unitOfWorkFactory, ITenantProvider tenantProvider)
{
if (unitOfWorkFactory is null)
{
throw new ArgumentNullException(nameof(unitOfWorkFactory), $"{nameof(unitOfWorkFactory)} cannot be null.");
}
if (tenantProvider is null)
{
throw new ArgumentNullException(nameof(tenantProvider), $"{nameof(tenantProvider)} cannot be null.");
}
var tenantId = tenantProvider.GetTenantId();
_unitOfWork = unitOfWorkFactory.Create(tenantId);
}
public void GetAllBlogs()
{
var repository = _unitOfWork.Repository();
var query = repository.MultipleResultQuery();
var blogs = repository.Search(query);
}
public void GetAllBlogsProjection()
{
var repository = _unitOfWork.Repository();
var query = repository.MultipleResultQuery()
.Select(selector => new
{
Name = selector.Title,
Link = selector.Url,
Type = selector.Type.Description
});
var blogs = repository.Search(query);
}
public void GetAllOrderedBlogs()
{
var repository = _unitOfWork.Repository();
IMongoDbQuery query;
IList blogs;
query = repository.MultipleResultQuery()
.OrderByDescending("Id");
blogs = repository.Search(query);
query = repository.MultipleResultQuery()
.OrderByDescending(blog => blog.Id);
blogs = repository.Search(query);
}
public void GetTopBlogs()
{
var repository = _unitOfWork.Repository();
var query = repository.MultipleResultQuery()
.Top(10);
var blogs = repository.Search(query);
}
public void GetPagedBlogs()
{
var repository = _unitOfWork.Repository();
var query = repository.MultipleResultQuery()
.Page(1, 20);
var blogs = repository.Search(query);
}
public void GetBlogsPagedList()
{
var repository = _unitOfWork.Repository();
var query = repository.MultipleResultQuery()
.Page(1, 20);
var blogs = repository.Search(query)
.ToPagedList(
query.Paging.PageIndex,
query.Paging.PageSize,
query.Paging.TotalCount);
}
public void GetFilteredBlogs()
{
var repository = _unitOfWork.Repository();
var query = repository.MultipleResultQuery()
.AndFilter(blog => blog.Url.StartsWith("/a/"))
.AndFilter(blog => blog.Title.StartsWith("a"))
.AndFilter(blog => blog.Posts.Any());
var blogs = repository.Search(query);
}
public void GetUrls()
{
var repository = _unitOfWork.CustomRepository();
var urls = repository.GetAllBlogUrls();
}
public void GetBlogByUrl()
{
var repository = _unitOfWork.Repository();
var query = repository.SingleResultQuery()
.AndFilter(blog => blog.Url.StartsWith("/a/"))
.OrderByDescending(blog => blog.Id);
var blogResult = repository.FirstOrDefault(query);
}
public void GetBlogById()
{
var repository = _unitOfWork.Repository();
var query = repository.SingleResultQuery()
.AndFilter(blog => blog.Id == 1);
var blogResult = repository.SingleOrDefault(query);
}
public void GetBlogByIdProjection()
{
var repository = _unitOfWork.Repository();
var query = repository.SingleResultQuery()
.AndFilter(blog => blog.Id == 1)
.Select(selector => new
{
selector.Id,
Name = selector.Title,
Link = selector.Url,
Type = selector.Type.Description
});
var blogResult = repository.SingleOrDefault(query);
}
public void ExistsBlog()
{
var repository = _unitOfWork.Repository();
var exists = repository.Any(blog => blog.Url.StartsWith("/a/"));
}
public void GetBlogCount()
{
var repository = _unitOfWork.Repository();
var count = repository.Count();
var longCount = repository.LongCount();
}
public void MaxBlogId()
{
var repository = _unitOfWork.Repository();
var id = repository.Max(blog => blog.Id);
}
public void MinBlogId()
{
var repository = _unitOfWork.Repository();
var id = repository.Min(blog => blog.Id);
}
public void AddBlog()
{
var repository = _unitOfWork.Repository();
repository.InsertOne(Seeder.SeedBlog(51));
_unitOfWork.SaveChanges();
}
public void UpdateBlog()
{
var repository = _unitOfWork.Repository();
repository.ReplaceOne(x => x.Id == id, model);
_unitOfWork.SaveChanges();
}
public void DeleteBlog()
{
var repository = _unitOfWork.Repository();
repository.DeleteOne(x => x.Id == id);
_unitOfWork.SaveChanges();
}
public void UpdateManyBlogs()
{
var repository = _unitOfWork.Repository();
repository.UpdateMany(
blog => blogIds.Contains(blog.Id),
new Dictionary>, object>
{
{ blog => blog.Title, "updated-title" }
});
_unitOfWork.SaveChanges();
}
public void BulkWriteBlogs()
{
var repository = _unitOfWork.Repository();
var requests = new List>();
foreach (var blogId in blogIds)
{
var filter = Builders.Filter.Eq(blog => blog.Id, blogId);
var definition = Builders.Update.Set(blog => blog.Title, $"a{blogId}-updated-title");
requests.Add(new UpdateOneModel(filter, definition));
}
repository.BulkWrite(requests);
_unitOfWork.SaveChanges();
}
```
The operations above are also available as async.
Please check some available samples [here](https://github.com/ffernandolima/mongo-db-data-access/tree/main/samples)
## 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.
