Nautilus.DataProvider.PostgreSql
1.0.1-alpha
dotnet add package Nautilus.DataProvider.PostgreSql --version 1.0.1-alpha
NuGet\Install-Package Nautilus.DataProvider.PostgreSql -Version 1.0.1-alpha
<PackageReference Include="Nautilus.DataProvider.PostgreSql" Version="1.0.1-alpha" />
<PackageVersion Include="Nautilus.DataProvider.PostgreSql" Version="1.0.1-alpha" />
<PackageReference Include="Nautilus.DataProvider.PostgreSql" />
paket add Nautilus.DataProvider.PostgreSql --version 1.0.1-alpha
#r "nuget: Nautilus.DataProvider.PostgreSql, 1.0.1-alpha"
#:package Nautilus.DataProvider.PostgreSql@1.0.1-alpha
#addin nuget:?package=Nautilus.DataProvider.PostgreSql&version=1.0.1-alpha&prerelease
#tool nuget:?package=Nautilus.DataProvider.PostgreSql&version=1.0.1-alpha&prerelease
Nautilus.DataProvider.PostgreSql
A PostgreSQL data provider implementation for the Nautilus ecosystem. This library provides a concrete implementation of DataProviderBase from Nautilus.Base, enabling seamless database operations with PostgreSQL through a consistent, database-agnostic API.
Features
- PostgreSQL-Specific Implementation: Full support for PostgreSQL including schemas, UUIDs, and native data types
- Automatic Migrations:
PostgreSqlMigratorfor creating tables with foreign key dependency resolution - Type Mapping: Automatic .NET to PostgreSQL type mapping via
PostgreSqlDataTypeMapper - CRUD Operations: Complete Create, Read, Update, Delete support (inherited from DataProviderBase)
- Async/Await: All operations have async variants
- Schema Support: Configurable schema (defaults to "public")
- Parameterized Queries: SQL injection protection through parameterized commands
- Stored Procedures: Full support for PostgreSQL functions/procedures with multiple result sets
- Dapper Integration: Leverages Dapper for efficient micro-ORM operations
Installation
Install the package via NuGet:
dotnet add package Nautilus.DataProvider.PostgreSql
Or via the Package Manager Console:
Install-Package Nautilus.DataProvider.PostgreSql
Quick Start
Define an Entity with Attributes
using Nautilus.Base.Data.ModelBase;
using Nautilus.Base.Data.Attributes;
// Basic entity with table and column mapping
[NautilusTableAttribute("users")]
public class User : EntityBase<int>
{
[NautilusPrimaryKeyAttribute]
[NautilusAutoIncrementAttribute]
public int Id { get; set; }
[NautilusColumnAttribute("first_name")]
public string FirstName { get; set; }
[NautilusColumnAttribute("last_name")]
public string LastName { get; set; }
public string Email { get; set; }
}
// Entity with schema and foreign key
[NautilusTableAttribute("orders", Schema = "sales")]
public class Order : EntityBase<int>
{
[NautilusPrimaryKeyAttribute]
[NautilusAutoIncrementAttribute]
public int Id { get; set; }
public string OrderNumber { get; set; }
public decimal TotalAmount { get; set; }
[NautilusForeignKeyAttribute]
[ConstraintReferenceForeignKey(typeof(User), "Id", true, true)]
public int UserId { get; set; }
}
Initialize the PostgreSQL Database
using Nautilus.DataProvider.PostgreSql;
using Nautilus.Base.Configuration;
// Load configuration from appsettings.json
IConfigurationRoot config = AppSettingJsonConfiguration.GetConfiguration("appsettings.json");
var appSettings = new AppSettings();
config.Bind(appSettings);
var providerSetting = appSettings.DatabaseProviders["DefaultConnection"];
// Create the data provider
var dataProvider = new PostgreSqlDatabase(providerSetting);
Basic CRUD Operations
// Insert a new user
var newUser = new User
{
FirstName = "John",
LastName = "Doe",
Email = "john.doe@example.com"
};
object insertedId = dataProvider.Save(newUser);
// Get a single entity by primary key
User user = dataProvider.Get<User>(123);
// Get all entities
IEnumerable<User> allUsers = dataProvider.GetAll<User>();
// Get with where clause
var whereParams = new Dictionary<string, object>
{
["Email"] = "user@example.com"
};
User user = dataProvider.Get<User>(whereParams);
// Update existing entity
user.FirstName = "Jane";
int affected = dataProvider.Update(user);
// Delete by primary key
int deleted = dataProvider.Delete<User>(123);
Async Operations
// Async insert
object insertedId = await dataProvider.SaveAsync(newUser);
// Async get by primary key
User user = await dataProvider.GetAsync<User>(123);
// Async get all
IEnumerable<User> users = await dataProvider.GetAllAsync<User>();
// Async update
int affected = await dataProvider.UpdateAsync(user);
// Async delete
int deleted = await dataProvider.DeleteAsync<User>(123);
Bulk Operations
// Bulk insert/update multiple entities efficiently
var users = new List<User>
{
new User { FirstName = "John", LastName = "Doe", Email = "john@example.com" },
new User { FirstName = "Jane", LastName = "Smith", Email = "jane@example.com" },
new User { FirstName = "Bob", LastName = "Johnson", Email = "bob@example.com" }
};
IEnumerable<object> insertedIds = dataProvider.SaveBulk(users);
// Async bulk operations
IEnumerable<object> insertedIds = await dataProvider.SaveBulkAsync(users);
Database Management
// Check if database exists
bool exists = dataProvider.DatabaseExists();
// Create database (if not exists)
dataProvider.CreateDatabase();
// Check database connection
bool isConnected = dataProvider.CheckConnection();
Database Migration
using Nautilus.DataProvider.PostgreSql;
// Create a migrator
var migrator = new PostgreSqlMigrator(
providerSetting,
() => dataProvider.CreateConnection(),
() => dataProvider.CreateDatabase()
);
// Add tables for migration
migrator.AddTable<User>()
.AddTable<Order>()
.AddTable<Product>();
// Run the migration (creates tables with FK dependency resolution)
migrator.Run();
API Reference
PostgreSqlDatabase
Concrete implementation of DataProviderBase for PostgreSQL.
Constructors
| Constructor | Description |
|---|---|
PostgreSqlDatabase(DatabaseProviderSetting providerSetting) |
Creates a new instance with full configuration |
PostgreSqlDatabase(string key, string connectionString) |
Creates a new instance with simple connection string |
Properties
| Property | Type | Description |
|---|---|---|
Schema |
string |
PostgreSQL schema name (defaults to "public") |
Key Methods (inherited from DataProviderBase)
| Method | Returns | Description |
|---|---|---|
Get<T>(primaryKey) |
T |
Gets a single entity by primary key |
Get<T>(where) |
T |
Gets a single entity matching the where clause |
GetAll<T>() |
IEnumerable<T> |
Gets all entities of type T |
GetAll<T>(where) |
IEnumerable<T> |
Gets all entities matching the where clause |
Save(model) |
object |
Inserts or updates an entity |
SaveBulk(models) |
IEnumerable<object> |
Bulk insert/update multiple entities |
Update(model) |
int |
Updates an existing entity (returns affected rows) |
Delete<T>(primaryKey) |
int |
Deletes an entity by primary key |
GetRecordsCount<T>() |
long |
Gets the total record count for type T |
Async Methods
| Method | Returns | Description |
|---|---|---|
GetAsync<T>(primaryKey) |
Task<T> |
Async variant of Get by primary key |
GetAsync<T>(where) |
Task<T> |
Async variant of Get with where clause |
GetAllAsync<T>() |
Task<IEnumerable<T>> |
Async variant of GetAll |
SaveAsync(model) |
Task<object> |
Async variant of Save |
SaveBulkAsync(models) |
Task<IEnumerable<object>> |
Async variant of SaveBulk |
UpdateAsync(model) |
Task<int> |
Async variant of Update |
DeleteAsync<T>(primaryKey) |
Task<int> |
Async variant of Delete |
GetRecordsCountAsync<T>() |
Task<long> |
Async variant of GetRecordsCount |
Database Management Methods
| Method | Returns | Description |
|---|---|---|
DatabaseExists() |
bool |
Checks if the database exists |
CreateDatabase() |
void |
Creates the database if it doesn't exist |
CheckConnection() |
bool |
Checks if the database connection is valid |
CreateConnection() |
DbConnection |
Creates and opens a new PostgreSQL connection (overrides base) |
GetAllDatabaseNameAsync() |
Task<IList<string>> |
Gets all database names from PostgreSQL asynchronously |
Database Introspection Methods
| Method | Returns | Description |
|---|---|---|
GetTables() |
IEnumerable<TableInfo> |
Gets table information (schema, name, owner) for current schema |
GetTablesAsync() |
Task<IEnumerable<TableInfo>> |
Async variant of GetTables |
Query Methods
| Method | Returns | Description |
|---|---|---|
ExecuteQuery<T>(options) |
IEnumerable<T> |
Executes a paginated query |
ExecuteQueryAsync<T>(options) |
Task<IEnumerable<T>> |
Async paginated query |
ExecuteQuery(sql) |
Dictionary<string, object> |
Executes raw SQL query |
ExecuteQueryAsync(sql) |
Task<Dictionary<string, object>> |
Async raw SQL query |
ExecuteNonQuery(sql) |
int |
Executes a non-query SQL statement |
ExecuteNonQueryAsync(sql) |
Task<int> |
Async non-query SQL statement |
ExecuteReader(sql) |
IEnumerable<Dictionary<string, object>> |
Executes SQL and returns multiple rows |
Stored Procedures
| Method | Returns | Description |
|---|---|---|
ExecuteStoredProcedure<T>(spName, parameters) |
T |
Executes a stored procedure returning single result |
ExecuteStoredProcedureList<T>(spName, parameters) |
IEnumerable<T> |
Executes a stored procedure returning list |
ExecuteStoredProcedureList<T1, T2>(...) |
(IEnumerable<T1>, T2) |
Executes SP returning two result sets |
ExecuteStoredProcedureList<T1, T2, T3>(...) |
(IEnumerable<T1>, T2, T3) |
Executes SP returning three result sets |
Utility Methods
| Method | Returns | Description |
|---|---|---|
CreateDbParameter(name, value) |
DbParameter |
Creates a PostgreSQL parameter with automatic type conversion (enums → int) |
PostgreSqlMigrator
Database migration tool for creating PostgreSQL tables.
Constructor
| Parameter | Type | Description |
|---|---|---|
databaseProviderSetting |
DatabaseProviderSetting |
Database configuration |
createConnectionFunc |
Func<DbConnection> |
Function to create database connections |
createDatabaseFunc |
Action |
Optional action to create the database |
Methods
| Method | Returns | Description |
|---|---|---|
AddTable<TModel>() |
IDbMigrator |
Adds a model type for migration (generic) |
AddTable(Type modelType) |
IDbMigrator |
Adds a model type for migration (reflection) |
Run() |
void |
Executes the migration |
The migrator automatically:
- Resolves foreign key dependencies before creating tables
- Creates tables with the correct PostgreSQL data types
- Handles primary keys, auto-increment, and constraints
- Supports ON DELETE CASCADE and ON UPDATE CASCADE
PostgreSqlDataTypeMapper
Maps .NET types to PostgreSQL data types.
Properties
| Property | Type | Description |
|---|---|---|
SimpleTypeMappings |
Dictionary<string, string> (static) |
Maps .NET type full names to PostgreSQL type names for types not requiring custom attributes |
Type Mappings
| .NET Type | PostgreSQL Type | Notes |
|---|---|---|
Int16 |
smallint |
2-byte integer |
Int32 |
integer |
4-byte integer |
Int64 |
bigint |
8-byte integer |
String |
text or varchar(n) |
Use [NautilusVarcharAttribute] for varchar |
Guid |
uuid |
UUID with optional auto-generation |
Decimal |
decimal or money |
Use [NautilusDecimalAttribute] to specify |
Double |
float8 |
Double precision |
DateTime |
time |
Time without time zone |
DateTimeOffset |
timestamptz |
Time with time zone |
Boolean |
bool |
Boolean |
Byte[] |
bytea |
Binary data |
DateOnly |
date |
Date without time |
Enum |
integer |
Stored as integer |
Simple Type Mappings Reference
| .NET Type | PostgreSQL Type |
|---|---|
System.Int16 |
smallint |
System.Int64 |
bigint |
System.Guid |
uuid |
System.Double |
float8 |
System.DateTime |
time |
System.DateTimeOffset |
timestamptz |
System.Boolean |
bool |
System.DateOnly |
date |
Usage Patterns
Entity Mapping with Attributes
// Simple mapping - uses class name for table
public class Category : EntityBase<int>
{
[NautilusPrimaryKeyAttribute]
public int Id { get; set; }
public string Name { get; set; }
}
// Maps to table: Category
// Custom table name with schema
[NautilusTableAttribute("categories", Schema = "inventory")]
public class Category : EntityBase<int>
{
[NautilusPrimaryKeyAttribute]
public int Id { get; set; }
public string Name { get; set; }
}
// Maps to: inventory.categories
// Column name overrides with data type attributes
[NautilusTableAttribute("users")]
public class User : EntityBase<int>
{
[NautilusPrimaryKeyAttribute]
[NautilusAutoIncrementAttribute]
[NautilusColumnAttribute("user_id")]
public int Id { get; set; }
[NautilusVarcharAttribute(100)]
[NautilusColumnAttribute("full_name")]
public string FullName { get; set; }
[NautilusNotNullAttribute]
public string Email { get; set; }
}
Migration with Foreign Keys
// Define related entities
[NautilusTableAttribute("authors")]
public class Author : EntityBase<int>
{
[NautilusPrimaryKeyAttribute]
[NautilusAutoIncrementAttribute]
public int Id { get; set; }
[NautilusVarcharAttribute(200)]
public string Name { get; set; }
}
[NautilusTableAttribute("books")]
public class Book : EntityBase<int>
{
[NautilusPrimaryKeyAttribute]
[NautilusAutoIncrementAttribute]
public int Id { get; set; }
[NautilusVarcharAttribute(200)]
public string Title { get; set; }
// Foreign key with cascade actions
[NautilusForeignKeyAttribute]
[ConstraintReferenceForeignKey(typeof(Author), "Id", OnDeleteCascade: true, OnUpdateCascade: true)]
public int AuthorId { get; set; }
}
// Run migration - tables are created in dependency order
var migrator = new PostgreSqlMigrator(providerSetting, () => connection, () => database.CreateDatabase());
migrator.AddTable<Author>()
.AddTable<Book>()
.Run();
Schema Configuration
// Using appsettings.json
{
"DatabaseProviders": {
"DefaultConnection": {
"Key": "DefaultConnection",
"ProviderType": "PostgreSql",
"ConnectionString": "Host=localhost;Port=5432;Database=mydb;Username=user;Password=pass",
"Schema": "myschema",
"Active": true,
"UseExistingDatabase": false
}
}
}
// The provider will use the configured schema
var provider = new PostgreSqlDatabase(providerSetting);
// provider.Schema == "myschema"
// Or set schema directly
provider.Schema = "public";
Raw SQL Execution
// Execute raw SQL with parameters
string sql = "SELECT * FROM users WHERE created_at > @cutoffDate";
var parameters = new Dictionary<string, object>
{
["cutoffDate"] = new DateTime(2024, 1, 1)
};
var results = dataProvider.ExecuteQuery(sql, parameters);
// Execute non-query SQL
string updateSql = "UPDATE products SET price = price * 1.1 WHERE category = @category";
var parameters = new Dictionary<string, object> { ["category"] = "Electronics" };
int affected = dataProvider.ExecuteNonQuery(updateSql, parameters);
Stored Procedure Execution
// Execute stored procedure returning single result
var parameters = new Dictionary<string, object>
{
["UserId"] = 123
};
User user = dataProvider.ExecuteStoredProcedure<User>("get_user_by_id", parameters);
// Execute stored procedure returning list
IEnumerable<Order> orders = dataProvider.ExecuteStoredProcedureList<Order>(
"get_user_orders",
parameters
);
// Execute stored procedure returning multiple result sets
var (ordersList, summary) = dataProvider.ExecuteStoredProcedureList<Order, OrderSummary>(
"get_user_order_summary",
parameters
);
Working with UUID Primary Keys
[NautilusTableAttribute("products")]
public class Product : EntityBase<Guid>
{
[NautilusPrimaryKeyAttribute(AutoGenerateGuid = true)]
public Guid Id { get; set; }
[NautilusVarcharAttribute(200)]
public string Name { get; set; }
public decimal Price { get; set; }
}
// On insert, PostgreSQL's gen_random_uuid() is used
var product = new Product
{
Name = "New Product",
Price = 29.99m
};
dataProvider.Save(product);
// product.Id is now set to the generated UUID
Database Introspection
// Get all tables in the current schema
IEnumerable<TableInfo> tables = dataProvider.GetTables();
foreach (var table in tables)
{
Console.WriteLine($"Schema: {table.SchemaName}, Table: {table.TableName}, Owner: {table.TableOwner}");
}
// Async variant
IEnumerable<TableInfo> tables = await dataProvider.GetTablesAsync();
// Get all database names
IList<string> databases = await dataProvider.GetAllDatabaseNameAsync();
foreach (var db in databases)
{
Console.WriteLine($"Database: {db}");
}
Architecture
Nautilus.DataProvider.PostgreSql follows the Provider Pattern established by Nautilus.Base, providing a concrete PostgreSQL implementation while maintaining a consistent API.
Application Layer
(Uses DataProviderBase - database-agnostic code)
inherits
DataProviderBase
(Abstract base class with CRUD, Query, Pagination from Nautilus.Base)
implements
PostgreSqlDatabase (This Library)
- CreateConnection() -> NpgsqlConnection
- CreateDatabase() -> PostgreSQL-specific database creation
- Save/SaveAsync() -> PostgreSQL INSERT with RETURNING clause
- UpdateAsync() -> PostgreSQL UPDATE with lowercase column names
- CreateDbParameter() -> NpgsqlParameter
Key Design Principles
- PostgreSQL-Specific: Leverages Npgsql and PostgreSQL features (UUIDs, schemas, RETURNING clause)
- Dependency Resolution: Migrator automatically resolves foreign key dependencies
- Type Mapping: Automatic .NET to PostgreSQL type mapping
- SQL Injection Protection: All values are parameterized
- Async-First: All operations have async variants
Project Structure
src/Nautilus.DataProvider.PostgreSql/
├── PostgreSqlDatabase.cs # Main data provider implementation
├── PostgreSqlMigrator.cs # Database migration tool
├── PostgreSqlDataTypeMapper.cs # .NET to PostgreSQL type mapper
└── _globalusings.cs # Global usings
Security
Nautilus.DataProvider.PostgreSql includes built-in protection against SQL injection attacks:
SQL Injection Prevention
All values are passed as parameters, never concatenated into SQL:
// Safe - values are parameterized
var whereParams = new Dictionary<string, object>
{
["Email"] = "user'; DROP TABLE users; --"
};
var user = dataProvider.Get<User>(whereParams);
// The malicious input is treated as a literal string, not executable SQL
The library uses NpgsqlParameter for all parameter values, ensuring proper escaping and type handling.
Related Repositories
Nautilus.DataProvider.PostgreSql is part of the Nautilus ecosystem:
| Package | Description | Link |
|---|---|---|
Nautilus.Base |
Base abstractions and attributes for all data providers | GitHub |
Other data provider implementations:
Nautilus.DataProvider.MSSQL- Microsoft SQL Server supportNautilus.DataProvider.MongoDB- MongoDB support
License
This project is licensed under the Business Source License 1.1.
The license allows free commercial use while protecting the source code. The code will automatically convert to the MIT License on [Change Date], 3 years after the first publication.
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
Support
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Acknowledgments
Nautilus.DataProvider.PostgreSql is part of the Nautilus ecosystem - a collection of .NET libraries designed to simplify common development tasks.
Related Nautilus packages:
- Nautilus.Base - Foundation for data access abstraction
- Nautilus.FluentResult - Type-safe result pattern
- Nautilus.HttpClient - Fluent HTTP client
- Nautilus.HandlerPattern - Request/response pattern with pipelines
Built with:
Note: This library is in active development. API changes may occur before version 1.0.0.
| 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 was computed. 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. |
-
net8.0
- Dapper (>= 2.1.35)
- Nautilus.Base (>= 0.0.11-preview)
- Npgsql (>= 8.0.3)
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 |
|---|---|---|
| 1.0.1-alpha | 83 | 12/31/2025 |
| 0.0.2-preview | 277 | 2/12/2023 |
| 0.0.1-preview | 224 | 2/12/2023 |