CoreDatabase 2026.6.11
See the version list below for details.
dotnet add package CoreDatabase --version 2026.6.11
NuGet\Install-Package CoreDatabase -Version 2026.6.11
<PackageReference Include="CoreDatabase" Version="2026.6.11" />
<PackageVersion Include="CoreDatabase" Version="2026.6.11" />
<PackageReference Include="CoreDatabase" />
paket add CoreDatabase --version 2026.6.11
#r "nuget: CoreDatabase, 2026.6.11"
#:package CoreDatabase@2026.6.11
#addin nuget:?package=CoreDatabase&version=2026.6.11
#tool nuget:?package=CoreDatabase&version=2026.6.11
📚 SQL Server Provider - Guía de Uso Completa
🚀 Introducción
El SQL Server Provider es una librería moderna para .NET 10 que proporciona una API limpia, asíncrona y optimizada para interactuar con SQL Server. Cumple con los principios SOLID y las mejores prácticas de Clean Code de Robert C. Martin.
✅ Características Principales
- 🔄 Async/Await: Soporte completo para operaciones asíncronas con cancelación
- 🎯 Type-Safe: Mapeo fuertemente tipado de entidades
- ⚡ Alto Rendimiento: Caché de propiedades, TypeConverters optimizados, Span<T>/Memory<T>
- 🔒 Concurrencia: Control con SemaphoreSlim para transacciones
- 📊 Telemetría: Integración con DiagnosticSource para monitoreo
- 🛡️ Excepciones: Jerarquía de excepciones con contexto rico
- 🌊 Streaming: IAsyncEnumerable para procesar grandes volúmenes de datos
- ✅ Validación: Configuración validada con IValidateOptions
📋 Tabla de Contenido
- Configuración Inicial
- Operaciones Básicas
- Consultas con Parámetros
- Procedimientos Almacenados
- Operaciones Asíncronas
- Streaming de Datos
- Transacciones
- Operaciones Bulk
- Manejo de Errores
- Configuración Avanzada
- Mejores Prácticas
🛠️ Configuración Inicial
1. Instalación del Paquete
dotnet add package DevKit.ExecutionEngine.SqlServer
2. Configuración en Startup.cs
using DevKit.ExecutionEngine.SQLServer;
using DevKit.ExecutionEngine.SQLServer.Validation;
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Configuración básica
services.ConfigureAndValidateSqlOptions(options =>
{
options.ConnectionString = "Server=localhost;Database=MyDB;Trusted_Connection=true;";
options.CommandTimeout = 30;
options.BulkCopy.BulkCopyTimeout = 300;
options.BulkCopy.BatchSize = 1000;
});
// Registrar el provider
services.AddTransient<ISQLServerProvider, SQLServerProvider>();
}
}
3. Inyección de Dependencias
public class UserService
{
private readonly ISQLServerProvider _dbProvider;
public UserService(ISQLServerProvider dbProvider)
{
_dbProvider = dbProvider;
}
}
🔍 Operaciones Básicas
Consulta Simple
// Obtener todos los usuarios
public async Task<List<User>> GetAllUsersAsync()
{
string query = "SELECT Id, Name, Email FROM Users";
var users = await _dbProvider.ExecuteQueryAsListAsync<User>(
query,
reader => new User
{
Id = reader.GetInt32("Id"),
Name = reader.GetString("Name"),
Email = reader.GetString("Email")
});
return users.ToList();
}
Obtener un Solo Registro
// Obtener usuario por ID
public async Task<User> GetUserByIdAsync(int userId)
{
string query = "SELECT Id, Name, Email FROM Users WHERE Id = @Id";
var user = await _dbProvider.ExecuteQueryAsSingleAsync<User>(
query,
reader => new User
{
Id = reader.GetInt32("Id"),
Name = reader.GetString("Name"),
Email = reader.GetString("Email")
},
parameters => parameters.AddSqlParameter("Id", userId));
return user;
}
Consulta Escalar
// Contar usuarios
public async Task<int> GetUserCountAsync()
{
string query = "SELECT COUNT(*) FROM Users";
return await _dbProvider.ExecuteScalarAsync<int>(query);
}
📝 Consultas con Parámetros
Parámetros con Extensiones Especializadas
El proyecto incluye SqlParameterExtensions que proporciona métodos avanzados para manejo de parámetros:
Parámetros desde Objetos
public async Task<User> CreateUserAsync(User user)
{
string query = @"
INSERT INTO Users (Name, Email, Age, Active)
OUTPUT INSERTED.Id
VALUES (@Name, @Email, @Age, @Active)";
var userId = await _dbProvider.ExecuteScalarAsync<int>(query,
parameters => parameters.AddSqlParameters(user));
user.Id = userId;
return user;
}
Parámetros desde Diccionarios
public async Task<List<User>> SearchUsersAsync(Dictionary<string, object> filters)
{
string query = "SELECT Id, Name, Email FROM Users WHERE 1=1";
// Construir consulta dinámica con parámetros
var parameters = new Dictionary<string, object>();
if (filters.ContainsKey("Name"))
{
query += " AND Name LIKE @Name";
parameters["Name"] = $"%{filters["Name"]}%";
}
if (filters.ContainsKey("MinAge"))
{
query += " AND Age >= @MinAge";
parameters["MinAge"] = filters["MinAge"];
}
return (List<User>)await _dbProvider.ExecuteQueryAsListAsync<User>(
query,
reader => new User
{
Id = reader.GetInt32("Id"),
Name = reader.GetString("Name"),
Email = reader.GetString("Email")
},
parameters => parameters.AddSqlParameters(parameters));
}
Parámetros con Tipos Específicos
public async Task<bool> InsertProductAsync(Product product)
{
string query = @"
INSERT INTO Products (Name, Price, Description, Image, CategoryId)
VALUES (@Name, @Price, @Description, @Image, @CategoryId)";
await _dbProvider.ExecuteProcedureCommandAsync(query,
parameters =>
{
// Parámetro con tipo específico y tamaño
parameters.AddSqlParameter("Name", product.Name,
SqlDbType.NVarChar, 100);
// Parámetro decimal con precisión
parameters.AddSqlParameter("Price", product.Price,
SqlDbType.Decimal, precision: 18, scale: 2);
// Parámetro grande (texto largo)
parameters.AddSqlParameter("Description", product.Description,
SqlDbType.NVarChar, -1); // -1 = MAX
// Parámetro binario
parameters.AddSqlParameter("Image", product.ImageData,
SqlDbType.VarBinary);
// Parámetro de salida
parameters.AddSqlParameter("CategoryId", product.CategoryId,
direction: ParameterDirection.Input);
});
return true;
}
Parámetros con Logging
public async Task<User> GetUserWithLoggingAsync(int userId)
{
string query = "SELECT * FROM Users WHERE Id = @Id";
return await _dbProvider.ExecuteQueryAsSingleAsync<User>(
query,
reader => reader.GetEntity<User>(),
parameters => parameters.AddSqlParameter("Id", userId, logTo: Console.WriteLine));
}
Parámetros Posicionales
public async Task<List<User>> GetUsersByAgeAsync(int minAge)
{
string query = "SELECT Id, Name, Email, Age FROM Users WHERE Age >= @MinAge";
return (List<User>)await _dbProvider.ExecuteQueryAsListAsync<User>(
query,
reader => new User
{
Id = reader.GetInt32("Id"),
Name = reader.GetString("Name"),
Email = reader.GetString("Email"),
Age = reader.GetInt32("Age")
},
parameters => parameters.AddSqlParameter("MinAge", minAge));
}
Múltiples Parámetros
public async Task<List<User>> SearchUsersAsync(string name, int? minAge, string email)
{
string query = @"
SELECT Id, Name, Email, Age
FROM Users
WHERE (@Name IS NULL OR Name LIKE '%' + @Name + '%')
AND (@MinAge IS NULL OR Age >= @MinAge)
AND (@Email IS NULL OR Email = @Email)";
return (List<User>)await _dbProvider.ExecuteQueryAsListAsync<User>(
query,
reader => new User
{
Id = reader.GetInt32("Id"),
Name = reader.GetString("Name"),
Email = reader.GetString("Email"),
Age = reader.GetInt32("Age")
},
parameters =>
{
parameters.AddSqlParameter("Name", string.IsNullOrEmpty(name) ? (object)DBNull.Value : name);
parameters.AddSqlParameter("MinAge", minAge ?? (object)DBNull.Value);
parameters.AddSqlParameter("Email", string.IsNullOrEmpty(email) ? (object)DBNull.Value : email);
});
}
🗄️ Procedimientos Almacenados
Ejecutar SP con Resultados
public async Task<User> GetUserByStoredProcedureAsync(int userId)
{
return await _dbProvider.ExecuteProcedureAsSingleAsync<User>(
"sp_GetUserById",
reader => new User
{
Id = reader.GetInt32("Id"),
Name = reader.GetString("Name"),
Email = reader.GetString("Email")
},
parameters => parameters.AddSqlParameter("UserId", userId));
}
Ejecutar SP sin Resultados
public async Task UpdateUserLastLoginAsync(int userId)
{
await _dbProvider.ExecuteProcedureCommandAsync(
"sp_UpdateUserLastLogin",
parameters => parameters.AddSqlParameter("UserId", userId));
}
SP que Devuelve Lista
public async Task<List<User>> GetActiveUsersAsync()
{
return (List<User>)await _dbProvider.ExecuteProcedureAsListAsync<User>(
"sp_GetActiveUsers",
reader => new User
{
Id = reader.GetInt32("Id"),
Name = reader.GetString("Name"),
Email = reader.GetString("Email")
});
}
⚡ Operaciones Asíncronas
Configuración de Timeout
public async Task<List<User>> GetUsersWithTimeoutAsync()
{
string query = "SELECT * FROM Users WHERE Status = 'Active'";
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
try
{
return (List<User>)await _dbProvider.ExecuteQueryAsListAsync<User>(
query,
reader => new User
{
Id = reader.GetInt32("Id"),
Name = reader.GetString("Name"),
Email = reader.GetString("Email")
},
cancellationToken: cts.Token);
}
catch (OperationCanceledException)
{
// Manejar timeout
throw new TimeoutException("La consulta excedió el tiempo límite de 10 segundos");
}
}
Operación con Cancelación
public async IAsyncEnumerable<User> StreamUsersWithCancellationAsync(
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
string query = "SELECT Id, Name, Email FROM Users ORDER BY Id";
await foreach (var user in _dbProvider.StreamAsync<User>(query, cancellationToken: cancellationToken))
{
yield return user;
}
}
🌊 Streaming de Datos
Procesar Grandes Volúmenes
public async Task ProcessLargeDatasetAsync(string filePath)
{
await using var writer = new StreamWriter(filePath);
// Streaming de 1 millón de registros sin cargar todo en memoria
await foreach (var user in _dbProvider.StreamAsync<User>(
"SELECT Id, Name, Email FROM Users ORDER BY Id"))
{
// Procesar cada usuario individualmente
await writer.WriteLineAsync($"{user.Id},{user.Name},{user.Email}");
// Pequeña pausa para no sobrecargar
if (user.Id % 1000 == 0)
{
await Task.Delay(1);
}
}
}
Streaming con Mapeo Personalizado
public async IAsyncEnumerable<UserDto> StreamUserDtosAsync()
{
string query = @"
SELECT u.Id, u.Name, u.Email, p.ProfileType
FROM Users u
LEFT JOIN UserProfiles p ON u.Id = p.UserId";
await foreach (var user in _dbProvider.StreamAsync(
query,
reader => new UserDto
{
Id = reader.GetInt32("Id"),
Name = reader.GetString("Name"),
Email = reader.GetString("Email"),
ProfileType = reader.IsDBNull("ProfileType") ? "Basic" : reader.GetString("ProfileType")
}))
{
yield return user;
}
}
🔒 Transacciones
Transacción Simple
public async Task<bool> TransferFundsAsync(int fromAccountId, int toAccountId, decimal amount)
{
try
{
await _dbProvider.ExecuteInTransactionAsync(async (transaction) =>
{
// Debitar cuenta origen
await _dbProvider.ExecuteProcedureCommandAsync(
"sp_DebitAccount",
parameters =>
{
parameters.AddSqlParameter("AccountId", fromAccountId);
parameters.AddSqlParameter("Amount", amount);
});
// Acreditar cuenta destino
await _dbProvider.ExecuteProcedureCommandAsync(
"sp_CreditAccount",
parameters =>
{
parameters.AddSqlParameter("AccountId", toAccountId);
parameters.AddSqlParameter("Amount", amount);
});
return true;
}, IsolationLevel.ReadCommitted);
return true;
}
catch (Exception)
{
return false;
}
}
Transacción con Control de Concurrencia
public async Task<OrderResult> ProcessOrderAsync(Order order, List<OrderItem> items)
{
// El provider controla automáticamente la concurrencia con SemaphoreSlim
return await _dbProvider.ExecuteInTransactionAsync(async (transaction) =>
{
// Validar stock
foreach (var item in items)
{
var stock = await _dbProvider.ExecuteScalarAsync<int>(
"SELECT Stock FROM Products WHERE ProductId = @ProductId",
parameters => parameters.AddSqlParameter("ProductId", item.ProductId));
if (stock < item.Quantity)
{
throw new InvalidOperationException($"Stock insuficiente para producto {item.ProductId}");
}
}
// Crear orden
var orderId = await _dbProvider.ExecuteScalarAsync<int>(
"INSERT INTO Orders (CustomerId, TotalAmount) OUTPUT INSERTED.Id VALUES (@CustomerId, @Total)",
parameters =>
{
parameters.AddSqlParameter("CustomerId", order.CustomerId);
parameters.AddSqlParameter("Total", order.Total);
});
// Insertar items
foreach (var item in items)
{
await _dbProvider.ExecuteProcedureCommandAsync(
"sp_AddOrderItem",
parameters =>
{
parameters.AddSqlParameter("OrderId", orderId);
parameters.AddSqlParameter("ProductId", item.ProductId);
parameters.AddSqlParameter("Quantity", item.Quantity);
parameters.AddSqlParameter("Price", item.Price);
});
}
// Actualizar stock
foreach (var item in items)
{
await _dbProvider.ExecuteProcedureCommandAsync(
"sp_UpdateStock",
parameters =>
{
parameters.AddSqlParameter("ProductId", item.ProductId);
parameters.AddSqlParameter("Quantity", -item.Quantity);
});
}
return new OrderResult
{
Success = true,
OrderId = orderId,
Message = "Orden procesada exitosamente"
};
});
}
📦 Operaciones Bulk
Bulk Insert Simple
public async Task ImportUsersAsync(List<User> users)
{
if (users.Count == 0) return;
// Convertir a DataTable
var dataTable = new DataTable();
dataTable.Columns.Add("Id", typeof(int));
dataTable.Columns.Add("Name", typeof(string));
dataTable.Columns.Add("Email", typeof(string));
dataTable.Columns.Add("Age", typeof(int));
foreach (var user in users)
{
dataTable.Rows.Add(user.Id, user.Name, user.Email, user.Age);
}
// Bulk insert
await _dbProvider.ExecuteBulkInsertAsync("Users", dataTable);
}
Bulk Insert Configurado
public async Task ImportLargeDatasetAsync(List<User> users)
{
var dataTable = users.ToDataTable();
// Configurar opciones de bulk copy
var bulkOptions = new SqlBulkCopyOptions
{
CheckConstraints = true,
FireTriggers = false,
KeepIdentity = true,
KeepNulls = true,
TableLock = true
};
await _dbProvider.ExecuteBulkInsertAsync("Users", dataTable, bulkOptions);
}
⚠️ Manejo de Errores
Captura de Excepciones Específicas
public async Task<User> SafeGetUserAsync(int userId)
{
try
{
return await _dbProvider.ExecuteQueryAsSingleAsync<User>(
"SELECT * FROM Users WHERE Id = @Id",
reader => reader.GetEntity<User>(),
parameters => parameters.AddSqlParameter("Id", userId));
}
catch (SqlQueryException ex)
{
_logger.LogError(ex, "Error en consulta SQL: {CommandText}", ex.CommandText);
// Excepción con contexto rico
throw new BusinessException($"Error al obtener usuario {userId}", ex)
{
ErrorCode = "USER_NOT_FOUND",
CorrelationId = ex.CorrelationId
};
}
catch (SqlTimeoutException ex)
{
_logger.LogWarning(ex, "Timeout al obtener usuario {UserId}", userId);
throw new BusinessException("La operación tardó demasiado tiempo", ex)
{
ErrorCode = "TIMEOUT",
RetryAfter = TimeSpan.FromSeconds(5)
};
}
catch (SqlConnectionException ex)
{
_logger.LogCritical(ex, "Error de conexión a base de datos");
throw new BusinessException("No se pudo conectar a la base de datos", ex)
{
ErrorCode = "CONNECTION_ERROR"
};
}
}
Excepciones con Telemetría
public async Task<bool> SafeExecuteAsync(string operation)
{
try
{
await _dbProvider.ExecuteProcedureCommandAsync("sp_ProcessData");
return true;
}
catch (SqlServerProviderException ex)
{
// Las excepciones ya incluyen contexto para telemetría
var telemetryProperties = ex.ToTelemetryProperties();
_telemetry.TrackEvent("DatabaseError", telemetryProperties);
_logger.LogError(ex, "Error en operación {Operation}: {Message}",
operation, ex.Message);
return false;
}
}
⚙️ Configuración Avanzada
Configuración Completa de Opciones
services.ConfigureAndValidateSqlOptions(options =>
{
// Conexión
options.ConnectionString = builder.ConnectionString;
// Timeouts
options.CommandTimeout = 60;
options.BulkCopy.BulkCopyTimeout = 600;
options.BulkCopy.BatchSize = 5000;
// Pool de conexiones
options.MaxPoolSize = 100;
options.MinPoolSize = 5;
options.ConnectionTimeout = 30;
// Concurrencia
options.MaxConcurrentTransactions = 10;
// Telemetría
options.EnableDiagnosticSource = true;
options.EnableActivityTracking = true;
});
Validación Personalizada
public class CustomSqlOptionsValidator : IValidateOptions<SqlOptions>
{
public ValidateOptionsResult Validate(string name, SqlOptions options)
{
var failures = new List<string>();
if (string.IsNullOrWhiteSpace(options.ConnectionString))
failures.Add("ConnectionString es requerido");
if (options.CommandTimeout <= 0 || options.CommandTimeout > 3600)
failures.Add("CommandTimeout debe estar entre 1 y 3600 segundos");
if (options.BulkCopy.BatchSize <= 0)
failures.Add("BulkCopy.BatchSize debe ser mayor a 0");
return failures.Any()
? ValidateOptionsResult.Fail(failures)
: ValidateOptionsResult.Success;
}
}
// Registrar validador
services.AddSingleton<IValidateOptions<SqlOptions>, CustomSqlOptionsValidator>();
🎯 Mejores Prácticas
1. Usar Siempre Parámetros
// ❌ MAL - Vulnerable a SQL Injection
string query = $"SELECT * FROM Users WHERE Name = '{userName}'";
// ✅ BIEN - Seguro con parámetros
string query = "SELECT * FROM Users WHERE Name = @Name";
await _dbProvider.ExecuteQueryAsListAsync<User>(
query,
reader => reader.GetEntity<User>(),
parameters => parameters.AddSqlParameter("Name", userName));
2. Selección de Columnas Específicas
// ❌ MAL - Trae todas las columnas
string query = "SELECT * FROM Users";
// ✅ BIEN - Solo columnas necesarias
string query = "SELECT Id, Name, Email FROM Users WHERE Active = 1";
3. Paginación para Grandes Consultas
public async Task<PagedResult<User>> GetUsersPagedAsync(int page, int pageSize)
{
int offset = (page - 1) * pageSize;
string query = @"
SELECT Id, Name, Email
FROM Users
WHERE Active = 1
ORDER BY Id
OFFSET @Offset ROWS FETCH NEXT @PageSize ROWS ONLY";
var users = await _dbProvider.ExecuteQueryAsListAsync<User>(
query,
reader => new User
{
Id = reader.GetInt32("Id"),
Name = reader.GetString("Name"),
Email = reader.GetString("Email")
},
parameters =>
{
parameters.AddSqlParameter("Offset", offset);
parameters.AddSqlParameter("PageSize", pageSize);
});
// Obtener total
string countQuery = "SELECT COUNT(*) FROM Users WHERE Active = 1";
int total = await _dbProvider.ExecuteScalarAsync<int>(countQuery);
return new PagedResult<User>
{
Items = users.ToList(),
Total = total,
Page = page,
PageSize = pageSize,
TotalPages = (int)Math.Ceiling((double)total / pageSize)
};
}
4. Transacciones Cortas
// ❌ MAL - Transacción larga
public async Task ProcessLargeDataSetAsync(List<Data> items)
{
await _dbProvider.ExecuteInTransactionAsync(async (transaction) =>
{
foreach (var item in items) // 10,000 items
{
await ProcessItemAsync(item); // Operación lenta
}
});
}
// ✅ BIEN - Transacciones cortas o batch processing
public async Task ProcessLargeDataSetAsync(List<Data> items)
{
const int batchSize = 100;
for (int i = 0; i < items.Count; i += batchSize)
{
var batch = items.Skip(i).Take(batchSize).ToList();
await _dbProvider.ExecuteInTransactionAsync(async (transaction) =>
{
foreach (var item in batch)
{
await ProcessItemAsync(item);
}
});
}
}
5. Manejo Apropiado de Recursos
// ✅ BIEN - Usando await using para recursos asíncronos
public async Task ProcessWithStreamingAsync()
{
await foreach (var item in _dbProvider.StreamAsync<Data>("SELECT * FROM LargeTable"))
{
// Procesar item
await ProcessItemAsync(item);
// Liberar memoria periódicamente
if (item.Id % 1000 == 0)
{
GC.Collect(0, GCCollectionMode.Optimized);
}
}
}
6. Configuración de Timeouts Apropiados
// ✅ BIEN - Timeouts configurados según operación
public class DatabaseOperations
{
private readonly ISQLServerProvider _fastProvider; // 5s timeout
private readonly ISQLServerProvider _slowProvider; // 300s timeout
public async Task<List<User>> GetActiveUsersAsync()
{
// Operación rápida - timeout corto
return (List<User>)await _fastProvider.ExecuteQueryAsListAsync<User>(
"SELECT Id, Name FROM Users WHERE Active = 1");
}
public async Task<Report> GenerateComplexReportAsync()
{
// Operación compleja - timeout largo
return await _slowProvider.ExecuteQueryAsSingleAsync<Report>(
"EXEC sp_GenerateComplexReport");
}
}
� Referencia Rápida de Métodos
Consultas
ExecuteQueryAsSingleAsync<T>(query, expression, parameters, ct)
ExecuteQueryAsListAsync<T>(query, expression, parameters, ct)
ExecuteQueryAsDictionaryAsync(query, parameters, ct)
ExecuteQueryAsTableAsync(query, parameters, ct)
ExecuteScalarAsync<T>(query, parameters, ct)
Procedimientos Almacenados
ExecuteProcedureAsSingleAsync<T>(sp, expression, parameters, ct)
ExecuteProcedureAsListAsync<T>(sp, expression, parameters, ct)
ExecuteProcedureAsDictionaryAsync(sp, parameters, ct)
ExecuteProcedureAsTableAsync(sp, parameters, ct)
ExecuteProcedureCommandAsync(sp, parameters, ct)
Streaming
StreamAsync<T>(query, mapper, parameters, timeout, ct)
StreamProcedureAsync<T>(sp, parameters, timeout, ct)
Transacciones
ExecuteInTransactionAsync<T>(operation, isolationLevel)
ExecuteInTransaction<T>(operation, isolationLevel)
Bulk Operations
ExecuteBulkInsertAsync(table, dataTable, options)
📄 Licencia
Este proyecto está licenciado bajo MIT License. Ver archivo LICENSE para más detalles.
🤝 Contribuciones
Las contribuciones son bienvenidas. Por favor:
- Fork el repositorio
- Crear una rama de características
- Enviar un Pull Request con pruebas
- Seguir las guías de estilo del código
🎉 ¡Listo para usar!
Para cualquier pregunta o soporte, por favor abre un issue en el repositorio.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. 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 is compatible. 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. |
| .NET Framework | net48 is compatible. net481 was computed. |
-
.NETFramework 4.8
- CoreUtilerias (>= 2026.6.10)
- Microsoft.Data.SqlClient (>= 7.0.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Options (>= 10.0.9)
- System.Data.Common (>= 4.3.0)
- System.Threading.Tasks (>= 4.3.0)
-
net10.0
- CoreUtilerias (>= 2026.6.10)
- Microsoft.Data.SqlClient (>= 7.0.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Options (>= 10.0.9)
-
net8.0
- CoreUtilerias (>= 2026.6.10)
- Microsoft.Data.SqlClient (>= 7.0.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Options (>= 10.0.9)
-
net9.0
- CoreUtilerias (>= 2026.6.10)
- Microsoft.Data.SqlClient (>= 7.0.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Options (>= 10.0.9)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2026.7.28 | 30 | 7/28/2026 |
| 2026.7.27 | 37 | 7/28/2026 |
| 2026.6.11 | 198 | 6/10/2026 |
| 2026.6.10 | 121 | 6/10/2026 |
| 2026.6.9 | 124 | 6/10/2026 |
| 2026.3.6 | 366 | 3/6/2026 |
| 2026.2.27 | 331 | 2/27/2026 |
| 2026.1.21 | 397 | 1/22/2026 |
| 2026.1.18 | 361 | 1/15/2026 |
| 2026.1.17 | 361 | 1/13/2026 |
| 2026.1.16 | 359 | 1/13/2026 |
| 2026.1.15 | 358 | 1/13/2026 |
| 2026.1.14 | 367 | 1/13/2026 |
| 2026.1.13 | 357 | 1/12/2026 |
| 2026.1.12 | 348 | 1/12/2026 |
| 2026.1.11 | 356 | 1/12/2026 |
| 2025.12.4 | 542 | 12/4/2025 |
| 2025.12.3 | 998 | 12/3/2025 |
| 2025.11.30 | 807 | 12/1/2025 |
| 2025.11.26 | 506 | 11/26/2025 |