MongoDB Repository
Renamed: This project was renamed from Deveel.Repository to Kista on May 26, 2025. The name Kista is Old Norse for "chest" or "repository", better reflecting the project purpose as a data access framework.
| Feature | Status | Notes |
|---|---|---|
| Base Repository | ✅ | |
| Filterable | ✅ | |
| Queryable | ✅ | Via MongoFramework IQueryable |
| Pageable | ✅ | |
| Tracking | ✅ | MongoFramework change tracking |
| Multi-tenant | ✅ | Via Kista.MongoFramework.MultiTenant |
The MongoRepository<TEntity> class is an implementation of the repository pattern that stores entities in a MongoDB database, built on top of MongoFramework.
MongoFramework is a lightweight library that maps .NET objects to MongoDB documents using a design similar to Entity Framework Core.
Installation
dotnet add package Kista.MongoFramework
Registration
Use the fluent builder API to register the MongoDB driver:
// Program.cs
builder.Services.AddRepositoryContext()
.UseMongoDB<MyMongoContext>(b => b
.WithConnectionString("mongodb://localhost:27017/my_database"));
You can also use a builder delegate to configure the connection:
builder.Services.AddRepositoryContext()
.UseMongoDB<MyMongoContext>(b => b
.WithConnection(conn => conn.UseConnection("mongodb://localhost:27017/my_database")));
The following configuration methods are available on the MongoDB driver builder:
| Method | Description |
|---|---|
WithConnectionString(string) | Sets the MongoDB connection string. |
WithConnection(Action<MongoConnectionBuilder>) | Configures the connection using a builder delegate. |
WithLifetime(ServiceLifetime) | Sets the service lifetime (default: Scoped). |
WithLifecycle() | Enables lifecycle support (default: enabled) |
WithoutLifecycle() | Disables lifecycle support |
Custom Context Type
If you derive from MongoDbContext (or MongoDbTenantContext for multi-tenant scenarios), register your concrete type:
builder.Services.AddRepositoryContext()
.UseMongoDB<MyMongoDbContext>(b => b
.WithConnectionString("mongodb://..."));
Multi-tenant Support
Multi-tenant support uses Finbuckle.MultiTenant. First, configure Finbuckle:
builder.Services.AddMultiTenant<MongoDbTenantInfo>()
.WithConfigurationStore()
.WithRouteStrategy("tenant");
Then register a tenant-aware MongoDB context (derived from MongoDbTenantContext) and the repository:
builder.Services.AddRepositoryContext()
.UseMongoDB<MyMongoTenantContext>(b => b
.WithConnection(conn => conn.UseConnection("mongodb://...")))
.WithMongoMultiTenancy<MongoDbTenantInfo>(defaultConnection: "mongodb://...");
The tenant context resolves the correct database connection for each tenant automatically.
Lifecycle Support
The MongoDB driver provides MongoRepositoryLifecycleHandler<TEntity> for lifecycle orchestration. It is enabled by default and can be disabled via .WithoutLifecycle().
Handler Behavior
| Operation | Behavior |
|---|---|
ExistsAsync | Lists collection names on the database to check whether the entity's collection exists. |
CreateAsync | Creates the collection via CreateCollectionAsync, then builds all entity indexes defined in the MongoFramework entity mapping. |
DropAsync | Drops all indexes, then drops the collection. |
SeedAsync | Inserts data directly into the raw MongoDB collection via InsertManyAsync / InsertOneAsync. Supports IEnumerable<TEntity>, IEnumerable<object>, and single entities. |
Seeding Examples
Using a provider class:
public class ProductSeedProvider : IRepositorySeedDataProvider<Product> {
public IEnumerable<Product> GetSeedData() {
yield return new Product { Name = "Widget", Price = 9.99m };
yield return new Product { Name = "Gadget", Price = 24.99m };
}
IEnumerable<object> IRepositorySeedDataProvider.GetSeedData()
=> GetSeedData().Cast<object>();
}
// Program.cs
builder.Services.AddRepositoryContext()
.UseMongoDB<MyMongoContext>(b => b
.WithConnectionString("mongodb://..."))
.ConfigureLifecycle(options => {
options.SeedStrategy = SeedStrategy.Always;
})
.WithSeedData<Product, ProductSeedProvider>();
Using inline data (no provider class needed):
builder.Services.AddRepositoryContext()
.UseMongoDB<MyMongoContext>(b => b
.WithConnectionString("mongodb://..."))
.ConfigureLifecycle(options => {
options.SeedStrategy = SeedStrategy.Always;
})
.WithSeedData<Product>(new[] {
new Product { Name = "Widget", Price = 9.99m },
new Product { Name = "Gadget", Price = 24.99m }
});
The handler inserts the seed documents directly into the MongoDB collection via InsertManyAsync.
Disabling Lifecycle
builder.Services.AddRepositoryContext()
.UseMongoDB<MyMongoContext>(b => b
.WithConnectionString("mongodb://...")
.WithoutLifecycle());
Querying
MongoRepository<TEntity> implements IQueryableRepository<TEntity>, IFilterableRepository<TEntity>, and IPageableRepository<TEntity>.
With LINQ:
var items = repository.AsQueryable()
.Where(x => x.IsActive)
.OrderBy(x => x.Name)
.ToList();
With filter types:
// Lambda shorthand (extension method)
var items = await repository.FindAllAsync(x => x.IsActive);
// ExpressionQueryFilter
var filter = new ExpressionQueryFilter<MyEntity>(x => x.IsActive);
var items = await repository.FindAllAsync(new Query(filter));
// MongoDB-specific geo-distance filter
var geoFilter = new MongoGeoDistanceFilter(
fieldName: "Location",
center: new GeoPoint(lat, lon),
maxDistanceKm: 10);
var items = await repository.FindAllAsync(new Query(geoFilter));
Notes
- MongoFramework does not natively expose DI integration; the
AddMongoDbContextextensions provided by this package fill that gap. - Refer to the MongoFramework documentation for entity mapping and index configuration.
- Refer to the Finbuckle.MultiTenant documentation for multi-tenant configuration.