Dinaup.Database (.NET)
Dinaup.Database es una librería .NET (compatible con .NET Framework y .NET Core) que proporciona una interfaz simplificada para trabajar con PostgreSQL. Sus objetivos principales son:
Facilitar la conexión a bases de datos PostgreSQL, soportando SSL y cadenas de conexión en formatos estándar.
Realizar lecturas sencillas de datos (listas, diccionarios, modelos) sin tener que lidiar directamente con DataReaders.
Ofrecer métodos de inserción, actualización y "upsert" (inserción o actualización según la existencia de registros).
Soportar la lectura por lotes de grandes cantidades de datos.
Integrarse con clases modelo a través de interfaces simples para mapear resultados a objetos de negocio.
Segura Multithreading.
Reutilización de conexión.
Instalación
Desde NuGet:
dotnet add package Dinaup.Database
Github Dinaup.Database.
Clase Principal: PGClient
La clase PGClient
proporciona métodos para:
Conexión y reconexión a PostgreSQL (con SSL si se requiere).
Ejecución de sentencias SQL.
Lectura de resultados (listas, diccionarios, modelos).
Inserción, actualización, y operaciones de upsert.
Lectura de datos en lotes.
Propiedades Principales
IsConnected
(bool): Indica si la conexión está abierta.Host
,Port
,UserName
,Password
,DatabaseName
: Parámetros de conexión.UseSSL
: Indica si se usa SSL.Description
: Descripción opcional de la conexión.TablesAndColumns
: Diccionario opcional de tablas a columnas.
Establecer Conexión
Conexión con parámetros separados:
var client = new PGClient();
client.Connect("localhost", 5432, "myuser", "mypassword", "mydatabase");
if (client.IsConnected)
{
Console.WriteLine("Conexión establecida correctamente.");
}
Con SSL (cadena estilo URL):
string connectionString = "postgres://user:password@host:port/dbname?sslmode=require";
client.ConnectWithSSL(connectionString);
Con SSL (parámetros separados):
client.ConnectWithSSL("host", 5432, "user", "password", "databaseName");
Lectura de Datos
ReadValue(string SQL)
: Retorna un único valor (cadena).ReadList(string SQL)
: Retorna una lista de cadenas (asumiendo una sola columna).ReadDictionary(string SQL)
: Retorna unDictionary<string, string>
a partir de pares clave-valor.ReadDictionaryList(string SQL)
: Retorna una lista de diccionarios (una fila por diccionario).ReadObjectList<T>(string SQL)
(donde T: BaseModelConverter): Retorna una lista de objetos T mapeados desde la BD.
Ejemplos:
// Leer un valor único
var countStr = client.ReadValue("SELECT COUNT(*) FROM test_table;");
int totalRegistros = int.Parse(countStr);
// Leer una lista (una columna)
var nombres = client.ReadList("SELECT name FROM test_table ORDER BY id;");
foreach (var nombre in nombres)
{
Console.WriteLine(nombre);
}
// Leer una lista de diccionarios
var registros = client.ReadDictionaryList("SELECT id, name, value FROM test_table WHERE id < 10;");
foreach (var reg in registros)
{
Console.WriteLine($"ID: {reg["id"]}, Name: {reg["name"]}, Value: {reg["value"]}");
}
Lectura de Modelos
Si se dispone de clases que heredan de BaseModelConverter
, puede mapearse directamente:
public class TestModel : BaseModelConverter
{
public int Id { get; set; }
public string Name { get; set; }
public int Value { get; set; }
public override void FromDic(Dictionary<string, string> dic)
{
this.Id = dic.GetM("id").INT(0);
this.Name = dic.GetM("name");
this.Value = dic.GetM("value").INT(0);
}
public override string Table => "test_table";
public override string[] Fields => new[] { "id", "name", "value" };
public override string LastModifiedFieldDatetimeUTC => ""; // No usado en este ejemplo
}
// Ejemplo de uso
var modelos = client.ReadObjectList<TestModel>("SELECT * FROM test_table ORDER BY id;");
foreach (var m in modelos)
{
Console.WriteLine($"{m.Id} - {m.Name} - {m.Value}");
}
Inserción, Actualización y Upsert
InsertRecord(tableName, record)
: Inserta un diccionario como registro.InsertRecords(tableName, records)
: Inserta múltiples registros a la vez.UpdateRecord(tableName, dataDict, idField, idValue)
: Actualiza el registro cuyo campoidField
coincide conidValue
.InsertOrIgnoreRecord(tableName, dataDict)
: Inserta el registro si no hay conflicto.InsertOrUpdateRecord(tableName, dataDict, idField)
: Inserta o actualiza según exista el registro.InsertOrUpdateRecords(tableName, dataDicts, idField)
: Inserta o actualiza múltiples registros.
Ejemplo: Insertar un registro
var nuevoRegistro = new Dictionary<string, string>
{
{"name", "NuevoNombre"},
{"value", "123"}
};
int rowsAffected = client.InsertRecord("test_table", nuevoRegistro);
Console.WriteLine("Filas insertadas: " + rowsAffected);
Ejemplo: Actualizar un registro
var datosActualizar = new Dictionary<string, string>
{
{"value", "999"}
};
int filasActualizadas = client.UpdateRecord("test_table", datosActualizar, "id", "1");
Console.WriteLine("Filas actualizadas: " + filasActualizadas);
Ejemplo: Upsert (insertar o actualizar)
var registroUpsert = new Dictionary<string, string>
{
{"id", "100"},
{"name", "Registro100"},
{"value", "1000"}
};
int affected = client.InsertOrUpdateRecord("test_table", registroUpsert, "id");
Console.WriteLine("Filas modificadas: " + affected);
Lectura en Lotes (Batch Reading)
Para grandes cantidades de datos:
BatchReadDictionaries(description, countSQL, dataSQL, batchSize)
: Iterador que produce lotes de diccionarios.BatchReadObjects<T>(description, countSQL, dataSQL, batchSize)
: Igual que el anterior pero para objetos de tipo T.
Ejemplo:
var batches = client.BatchReadDictionaries(
"Lectura en lotes",
"SELECT COUNT(*) FROM test_table",
"SELECT id, name, value FROM test_table ORDER BY id",
1000
);
foreach (var batch in batches)
{
Console.WriteLine("Lote de " + batch.Count + " registros");
foreach (var reg in batch)
{
Console.WriteLine($"{reg["id"]} - {reg["name"]} - {reg["value"]}");
}
}
Clonar Conexiones
DuplicateConnection()
crea una nueva instancia PGClient
con la misma configuración y abre la conexión.
var repoClonado = client.DuplicateConnection();
if (repoClonado.IsConnected)
{
Console.WriteLine("Conexión clonada y funcionando.");
}
Manejo de Errores
Se pueden capturar excepciones con try...catch
.
try
{
client.ExecuteNonQuery("INSERT INTO test_table (name, value) VALUES ('Test', 1)");
}
catch (Exception ex)
{
Console.WriteLine("Error en la inserción: " + ex.Message);
}
Liberación de Recursos
PGClient
implementa IDisposable
, por lo que es recomendable usar using
:
using (var client = new PGClient())
{
client.Connect("localhost", 5432, "user", "pass", "db");
// ... Operaciones ...
}
// Aquí se libera la conexión automáticamente
Ejemplos Completos
Ejemplo 1: Leer todos los registros (c#)
var client = new PGClient();
client.Connect("localhost", 5432, "user", "password", "mydb");
var listaNombres = client.ReadList("SELECT name FROM test_table ORDER BY id;");
foreach (var nombre in listaNombres)
{
Console.WriteLine(nombre);
}
Ejemplo 2: Insertar y luego leer modelos (c#)
var client = new PGClient();
client.ConnectWithSSL("postgres://user:pass@host:port/mydb?sslmode=require");
// Insertar un registro
var nuevo = new Dictionary<string, string>
{
{"name", "NuevoRegistro"},
{"value", "100"}
};
client.InsertRecord("test_table", nuevo);
// Leer como objetos
var objetos = client.ReadObjectList<TestModel>("SELECT * FROM test_table WHERE name='NuevoRegistro'");
foreach (var obj in objetos)
{
Console.WriteLine($"{obj.Id}: {obj.Name} - {obj.Value}");
}
Ejemplo 3: Actualizar o Ignorar si existe (c#)
var client = new PGClient();
client.Connect("localhost", 5432, "user", "password", "mydb");
var registro = new Dictionary<string, string>
{
{"id", "1"},
{"name", "Test1"},
{"value", "999"}
};
// InsertOrUpdate
int afectadas = client.InsertOrUpdateRecord("test_table", registro, "id");
Console.WriteLine("Filas afectadas: " + afectadas);
Última actualización