DataAccess.MongoDB
What is MongoDB ?
MongoDB is a NoSQL cross-platform document-oriented database. It is one of the most popular databases available. MongoDB is developed by MongoDB Inc. and is published as free and open-source software.
MongoDB C#/.NET Driver is a official driver developed for your .Net application to work compatible with MongoDB.
Data Access with Milva
The library uses the Repository Design Pattern and MongoDB.Driver to access the database. It is essentially an abstraction above MongoDB.Driver. We recommend that you review the NoSql concepts, MongoDB, MongoDB.Driver and Repository Design Pattern topics before continuing. Because we will explain assuming you know the basics.
Features;
- With EntityBase mentioned in Milvasoft.Core layer, you can perform auditing automatically by inheriting only your entities.
- As you know, mongodb is not a relational database. That's why you can't
join
operation. For more readable code, pretends tojoin
like insql
. - It allows different people working on the same project to develop projects with exactly the same code standards and performance.
- Automatically converts DateTime values to
UTC
for you to develop Timezone standalone applications. - It allows you to easily perform client-side encryption with
AES
.
Components;
Base Repository : It is a class that contains dozens of methods such as pagination, sorting, insertion, deletion, update, and you can send most queries to the database with these methods parametrically. These methods are written in accordance with best practices prepared for MongoDB.Driver.
NoSqlRelationHelper : It provides the highest level of readability in cases where there is a DbRef reference from one collection to the other collection and enables the relevant data(s) to be retrieved.
Let's do some step-by-step examples with all of these components.
Usage
Create SampleUser, SampleRole and AccountAction class;
public class SampleUser : DocumentBase
{
public string Username { get; set; }
// Embedded document
public List<AccountAction> Actions { get; set; }
// DbRef to SampleRole collection
public MongoDBRef RoleReference { get; set; }
// Navigation property
[BsonIgnore]
public SampleRole Role { get; set; }
}
public class SampleRole : DocumentBase
{
public string Name { get; set; }
}
public class AccountAction : IEmbedded
{
public string Action { get; set; }
}
Best use case for library: Inherit collection entities from DocumentBase, implement IEmbedded interface to embedded document entities.
Register to required services to service collection;
services.AddMilvaMongoHelper(opt =>
{
opt.AddTenantIdSupport = true;
opt.MongoClientSettings = new MongoClientSettings
{
MinConnectionPoolSize = 400,
MaxConnectionPoolSize = 600,
Server = new MongoServerAddress("localhost")
};
opt.DatabaseName = "testDatabase";
opt.EncryptionKey = "2r5u8x/A?D(G-KaP";
opt.UseUtcForDateTimes = true;
});
services.AddScoped(typeof(IBaseRepository<>), typeof(BaseRepository<>));
It's time to use the structure we created;
public class UserService
{
private readonly IBaseRepository<SampleUser> _userRepository;
private readonly IBaseRepository<SampleRole> _roleRepository;
private readonly IMongoDatabase _mongoDatabase;
public UserService(IBaseRepository<SampleUser> userRepository,
IBaseRepository<SampleRole> roleRepository,
IMongoDatabase mongoDatabase)
{
_userRepository = userRepository;
_roleRepository = roleRepository;
_mongoDatabase = mongoDatabase;
}
public async Task DoSometingAsync()
{
var role = new SampleRole
{
Id = ObjectId.GenerateNewId(),
Name = "Sample Role"
};
// Optional. If you do not assign an id, Mongo Driver will automatically assign an id to the inserted record.
var firstUserId = ObjectId.GenerateNewId();
// You do not need to manually set the audit properties mentioned in the Entity Bases section. BaseRepository does this automatically.
var users = new List<SampleUser>
{
new SampleUser
{
Id = firstUserId,
Username = "testuser",
PhoneNumber = (EncryptedString)"+905xxxxxxxxx",
RoleReference = role.Id.GetMongoDBRef<SampleRole>(),
Actions = new List<AccountAction>
{
new AccountAction
{
Action = "Login"
}
}
},
new SampleUser
{
Id = ObjectId.GenerateNewId(),
Username = "testuser2",
PhoneNumber = (EncryptedString)"+905xxxxxxxxx",
RoleReference = role.Id.GetMongoDBRef<SampleRole>(),
Actions = new List<AccountAction>
{
new AccountAction
{
Action = "Logout"
}
}
}
};
await _roleRepository.AddAsync(role);
await _userRepository.AddRangeAsync(users);
// Gets first user with role. In other words, the join operation is done to the Role database table.
var firstUser = await _userRepository.GetByIdAsync(firstUserId);
// Finds the role the user is referencing from the SampleRole collection and maps it to the Role navigation property. If you want, you can send conditions and projections in other parameters while doing this.
await firstUser.MapReferenceAsync(_mongoDatabase, rr => rr.RoleReference, r => r.Role);
// Output : Sample Role
var roleName = firstUser.Role.Name;
// It paginates all the records in the database with 1 record on each page and returns the records on the 2nd page. This process takes place in the database.
var (usersInSecondPage, pageCount, totalDataCount) = await _userRepository.GetAsPaginatedAsync(pageIndex: 2, requestedItemCount: 1, orderByProps: null);
// Output : testuser2
var someUserUsername = usersInSecondPage.FirstOrDefault().Username;
}
}
For more methods from base repository and relation helper please see here and here.