Maurosoft.Net.RepositoryPattern
1.0.5
See the version list below for details.
dotnet add package Maurosoft.Net.RepositoryPattern --version 1.0.5
NuGet\Install-Package Maurosoft.Net.RepositoryPattern -Version 1.0.5
<PackageReference Include="Maurosoft.Net.RepositoryPattern" Version="1.0.5" />
<PackageVersion Include="Maurosoft.Net.RepositoryPattern" Version="1.0.5" />
<PackageReference Include="Maurosoft.Net.RepositoryPattern" />
paket add Maurosoft.Net.RepositoryPattern --version 1.0.5
#r "nuget: Maurosoft.Net.RepositoryPattern, 1.0.5"
#:package Maurosoft.Net.RepositoryPattern@1.0.5
#addin nuget:?package=Maurosoft.Net.RepositoryPattern&version=1.0.5
#tool nuget:?package=Maurosoft.Net.RepositoryPattern&version=1.0.5
Maurosoft Repository Pattern
Una libreria per .NET 9 che fornisce un’implementazione pulita ed estensibile del Repository Pattern per l’accesso a più database.
Aggiunge un livello di astrazione utilizzando RepoDB.Net e Dapper, offrendo un approccio unificato per interagire con SQL Server, MySQL e ClickHouse.
(Il supporto a PostgreSQL è attualmente in sviluppo 🚧)
✨ Funzionalità
- 🔗 Implementazione unificata del Repository Pattern
- ⚡ Registrazione semplificata repository tramite classe base
- 🛠 Supporto per più ORM: RepoDB.Net e Dapper
- 🗄 Compatibile con:
- Microsoft SQL Server
- MySQL
- ClickHouse
- PostgreSQL (in arrivo)
- ⚡ Ottimizzata per .NET 9
- ♻️ Supporto a transazioni con unit of work
- 🧩 Estendibile facilmente per nuovi provider
📦 Installazione
Aggiungi il pacchetto tramite NuGet:
dotnet add package Maurosoft.Net.RepositoryPattern
⚙️ Configurazione
La libreria utilizza un approccio multi–database configurabile tramite appsettings.json.
È possibile definire uno o più endpoint, ciascuno con il relativo provider, connection string e l’eventuale abilitazione del supporto alle Unit of Work.
Esempio di configurazione:
{
"Database": {
"Default": "PrimarySql",
"Endpoints": {
"PrimarySql": {
"Provider": "SqlServer",
"UnitOfWork": true,
"ConnectionString": "Data Source=server1;Initial Catalog=app;User Id=sa;Password=Pass@word1!;TrustServerCertificate=True;MultipleActiveResultSets=True;Application Name=Repository Pattern Library"
},
"SecondarySql": {
"Provider": "SqlServer",
"UnitOfWork": false,
"ConnectionString": "Data Source=server2;Initial Catalog=app;User Id=sa;Password=Pass@word1!;TrustServerCertificate=True;MultipleActiveResultSets=True;Application Name=Repository Pattern Library"
},
"MySqlMain": {
"Provider": "MySql",
"UnitOfWork": true,
"ConnectionString": "Server=server3;Port=3306;Database=app;User Id=root;Password=pass;"
}
"ClickHouseDW": {
"Provider": "ClickHouse",
"ConnectionString": "Host=server4;Port=8123;Database=dw;Username=default;Password="
}
}
}
}
🧩 IRepository<TEntity> Metodi — DB Support Draft
Legenda: ✅ Supported · ⚠️ Limited/Workaround · ❌ Not available / impractical
| Nome metodo | Descrizione | SqlServer | MySql | PostgreSQL | ClickHouse |
|---|---|---|---|---|---|
Attach(IUnitOfWork unitOfWork) |
Attaches this repository to a unit of work to share the same database transaction. | ✅ | ✅ | ✅ | ❌ |
EndPoint |
Gets the logical connection name used to resolve the IDataContext<TConnection>. |
✅ | ✅ | ✅ | ✅ |
Fields |
Gets the list of fields used in queries. | ✅ | ✅ | ✅ | ✅ |
Average(Expression<Func<TEntity, object>> field, Expression<Func<TEntity, bool>>? where = null) |
Calculates the average of the values of the specified field that satisfy an optional filter condition. | ✅ | ✅ | ✅ | ❌ |
AverageAsync(Expression<Func<TEntity, object>> field, Expression<Func<TEntity, bool>>? where = null) |
Calculates the average of the values of the specified field that satisfy an optional filter condition. | ✅ | ✅ | ✅ | ❌ |
BulkDelete(IEnumerable<TEntity> entities, Expression<Func<TEntity, object>>? qualifiers = null, int bulkCopyTimeout = 300, int batchSize = 10000) |
Performs a bulk delete on a collection of entities. | ✅ | ❌ | ❌ | ❌ |
BulkInsert(string tableName, IEnumerable<TEntity> entities, IEnumerable<DatabaseBulkInsertMapItem>? mappings = null, int bulkCopyTimeout = 300, int batchSize = 10000) |
Performs a bulk insert into the specified table. | ✅ | ✅ | ❌ | ❌ |
BulkInsert<T>(string tableName, IEnumerable<T> entities, Action<T, int, DataRow, DataTable> itemToRow, IDbTransaction? transaction, int? batchSize = null) |
Performs a bulk insert using a custom mapper from item to DataRow. |
✅ | ✅ | ❌ | ❌ |
BulkMerge(IEnumerable<TEntity> entities, Expression<Func<TEntity, object>>? qualifiers = null, int bulkCopyTimeout = 300, int batchSize = 10000) |
Performs a bulk merge (upsert) into a specific table for the current TEntity. |
✅ | ✅ | ❌ | ❌ |
BulkMerge(string tableName, IEnumerable<TEntity> entities, Expression<Func<TEntity, object>>? qualifiers = null, int bulkCopyTimeout = 300, int batchSize = 10000) |
Performs a bulk merge (upsert) into a specific table for the current TEntity. |
✅ | ✅ | ❌ | ❌ |
BulkMerge(string tableSource, string tableDestination, Expression<Func<TEntity, object>>? qualifiers = null, int bulkCopyTimeout = 300, int batchSize = 10000) |
Loads all rows from a source table into memory and performs a bulk merge into the destination table. | ✅ | ✅ | ❌ | ❌ |
CopyFrom(string endPointSource, string commandText, object? param = null, CommandType? commandType = null, int commandTimeout = 60, IEnumerable<DatabaseField>? qualifiers = null) |
Copies data from a specified source endpoint into the current repository endpoint by executing a query on the source and performing a bulk merge (upsert) into the current endpoint. | ✅ | ✅ | ✅ | ❌ |
Count(Expression<Func<TEntity, bool>>? where = null) |
Returns the number of entities that satisfy an optional filter condition. | ✅ | ✅ | ✅ | ❌ |
CountAsync(Expression<Func<TEntity, bool>>? where = null) |
Returns the number of entities that satisfy an optional filter condition. | ✅ | ✅ | ✅ | ❌ |
CreateTable(bool temporary = true, string name = "temp", string fields = "", bool dropIfExists = true, bool randomName = true) |
Creates a temporary or permanent table based on the provided options. | ✅ | ✅ | ✅ | ❌ |
Delete(object id) |
Deletes an entity by primary key. | ✅ | ✅ | ✅ | ❌ |
DropTable(bool temporary = true, string name = "temp") |
Drops a temporary or permanent table. | ✅ | ✅ | ✅ | ❌ |
ExecuteNonQuery(string commandText, object? param = null, CommandType? commandType = null, int commandTimeout = 60) |
Executes a non-query SQL command (e.g., INSERT, UPDATE, DELETE). | ✅ | ✅ | ✅ | ✅ |
GetAll(bool cache = false, bool invalidateCache = false, string cacheKey = "GetAll", TimeSpan? cacheDuration = null) |
Retrieves all entities, optionally leveraging a cache mechanism. | ✅ | ✅ | ✅ | ❌ |
Insert(TEntity entity, Func<TEntity, bool>? action = null) |
Inserts a single entity and optionally executes a post-insert action. | ✅ | ✅ | ✅ | ❌ |
InsertAll(IEnumerable<TEntity> entities) |
Inserts multiple entities in a set-based operation. | ✅ | ✅ | ✅ | ❌ |
Max(Expression<Func<TEntity, object>> field, Expression<Func<TEntity, bool>>? where = null) |
Calculates the maximum of the values of the specified field that satisfy an optional filter condition. | ✅ | ✅ | ✅ | ❌ |
MaxAsync(Expression<Func<TEntity, object>> field, Expression<Func<TEntity, bool>>? where = null) |
Calculates the maximum of the values of the specified field that satisfy an optional filter condition. | ✅ | ✅ | ✅ | ❌ |
Merge(TEntity entity, IEnumerable<DatabaseField>? qualifiers = null) |
Merges (upserts) a single entity using optional qualifiers. | ✅ | ✅ | ❌ | ❌ |
MergeAll(IEnumerable<TEntity> entities, Expression<Func<TEntity, object>> qualifiers) |
Merges (upserts) a sequence of entities using a lambda-based qualifier. | ✅ | ✅ | ❌ | ❌ |
MergeAll(IEnumerable<TEntity> entities, IEnumerable<DatabaseField> qualifiers) |
Merges (upserts) a sequence of entities using an explicit list of qualifier fields. | ✅ | ✅ | ❌ | ❌ |
MergeAll(IEnumerable<TEntity> entities, Expression<Func<TEntity, object>> qualifiers, IEnumerable<DatabaseField> fields) |
Merges (upserts) a sequence of entities specifying both qualifiers and an explicit field list. | ✅ | ✅ | ❌ | ❌ |
Min(Expression<Func<TEntity, object>> field, Expression<Func<TEntity, bool>>? where = null) |
Calculates the minimun of the values of the specified field that satisfy an optional filter condition. | ✅ | ✅ | ✅ | ❌ |
MinAsync(Expression<Func<TEntity, object>> field, Expression<Func<TEntity, bool>>? where = null) |
Calculates the minimun of the values of the specified field that satisfy an optional filter condition. | ✅ | ✅ | ✅ | ❌ |
Query(string commandText, object? param = null, CommandType? commandType = null, int commandTimeout = 60) |
Executes an ad-hoc SQL query and returns the results projected to TEntity. |
✅ | ✅ | ✅ | ✅ |
Query(Expression<Func<TEntity, bool>> where, bool cache = false, bool invalidateCache = false, string cacheKey = "Query", TimeSpan? cacheDuration = null) |
Queries entities using a LINQ where-clause and optional caching. | ✅ | ✅ | ✅ | ❌ |
QuerySingle(string commandText, object? param = null, CommandType? commandType = null, int commandTimeout = 60) |
Retrieves a single entity by predicate, applying ordering and an optional in-place update before returning it. | ✅ | ✅ | ✅ | ❌ |
QuerySingle(Expression<Func<TEntity, bool>> where, bool cache = false, bool invalidateCache = false, string cacheKey = "QuerySingle", TimeSpan? cacheDuration = null) |
Retrieves a single entity by predicate, applying ordering and an optional in-place update before returning it. | ✅ | ✅ | ✅ | ❌ |
QuerySingleWithUpdate<TEntityOut>(Expression<Func<TEntity, bool>> where, DatabaseSortDirection sortDirection, Func<TEntity, TEntityOut> orderByCriteria, Func<TEntity, TEntity>? funcUpdate) |
Retrieves a single entity by predicate, applying ordering and an optional in-place update before returning it. | ✅ | ✅ | ✅ | ❌ |
Update(TEntity? entity, IEnumerable<DatabaseField>? fields = null) |
Updates a single entity instance. | ✅ | ✅ | ✅ | ❌ |
Update(Expression<Func<TEntity, bool>> where, Func<TEntity, TEntity> fields) |
Updates the entities that matches the predicate by applying a field-transform function. | ✅ | ✅ | ✅ | ❌ |
🚀 Utilizzo
Un caso di utilizzo per copiare i dati di una tabella da 2 database diversi (MySql e SqlServer)
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Maurosoft.Net.RepositoryPattern.Interfaces;
using Maurosoft.Net.RepositoryPattern.Model;
using System.Data;
using Maurosoft.Net.RepositoryPattern;
using ZiggyCreatures.Caching.Fusion;
var host = Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(cfg =>
{
cfg.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
cfg.AddEnvironmentVariables();
})
.ConfigureServices((ctx, services) =>
{
services.AddRepositoryPattern(ctx.Configuration);
services.AddKeyedScoped<IRepository<User>>("UserRepositoryMySql", (c, _) => new RepositoryPattern.Services.Repository<User>(c.GetRequiredService<IDbConnectionFactory>(), c.GetRequiredService<IFusionCache>(), "MySql"));
services.AddKeyedScoped<IRepository<User>>("UserRepositorySqlServer", (c, _) => new RepositoryPattern.Services.Repository<User>(c.GetRequiredService<IDbConnectionFactory>(), c.GetRequiredService<IFusionCache>(), "SqlServer"));
})
.Build();
/*
- Sorgente: legge da MySql usando la SELECT (parametrizzata).
- Destinazione: il repository è attaccato a SqlServer → scrive su SQL Server.
- DatabaseField("UserName") definisce la/e colonne chiave di corrispondenza per il merge:
- se UserName esiste già nel target → UPDATE della riga,
- altrimenti → INSERT.
- Ritorno: rowAffected = numero di righe inserite/aggiornate nel target.
*/
using (var scoped = host.Services.CreateScope())
{
var repo = scoped.ServiceProvider.GetRequiredKeyedService<IRepository<User>>("UserRepositorySqlServer");
var uow = scoped.ServiceProvider.GetRequiredKeyedService<IUnitOfWork>("UnitOfWorkSqlServer");
try
{
repo.Attach(uow);
uow.Begin();
// Merge degli utenti ... utilizzando il campo Username come chiave.
var rowAffected = repo.CopyFrom(
"MySql", // endpoint sorgente (MySQL)
"SELECT * FROM Users Where UserId > @UserId", // query sorgente
new { UserId = 1 }, // parametri query
CommandType.Text, // tipo comando
60, // timeout esecuzione (sec.)
[ new DatabaseField("UserName") ] // chiavi di merge (se non specificata, viene utilizzata la chiave primaria)
);
uow.Commit();
Console.WriteLine($"Rows Affected: {rowAffected}");
}
catch
{
uow.Rollback();
throw;
}
}
[Table("Users")]
public class User
{
public int UserId { get; set; }
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
public string UserName { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
}
🛡 Requisiti
- .NET 9
- Uno o più database supportati in esecuzione
📌 Roadmap
- Supporto SQL Server
- Supporto MySQL
- Supporto ClickHouse
- Supporto PostgreSQL
- Integrazione avanzata con caching
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- ClickHouse.Client (>= 7.14.0)
- Dapper (>= 2.1.66)
- Maurosoft.RepoDb (>= 1.0.2)
- Maurosoft.RepoDb.MySqlConnector (>= 1.0.1)
- Maurosoft.RepoDb.PostgreSql (>= 1.0.1)
- Maurosoft.RepoDb.PostgreSql.BulkOperations (>= 1.0.1)
- Maurosoft.RepoDb.SqlServer (>= 1.0.1)
- Maurosoft.RepoDb.SqlServer.BulkOperations (>= 1.0.1)
- Microsoft.Data.SqlClient (>= 6.1.2)
- Microsoft.Extensions.Configuration (>= 9.0.9)
- Microsoft.Extensions.Configuration.Json (>= 9.0.9)
- MySqlConnector (>= 2.4.0)
- Npgsql (>= 9.0.4)
- ZiggyCreatures.FusionCache (>= 2.4.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.