SQL-specific data access layer providing abstract base classes for SQL database operations.
C:\Source\Birko.Data.SQL\
- Provides abstract base classes for SQL database operations
- Defines connector pattern for database connections
- Implements common SQL functionality (tables, attributes, exceptions)
Base class for synchronous SQL stores.
DB Connector- Database connection (protected set for derived classes)- Abstract methods for CRUD operations
- Automatic connection management via Settings
Extends DataBaseStore with bulk operations.
- Optimized for bulk inserts/updates/deletes
- Uses database-specific bulk operations where available
Base class for asynchronous SQL stores.
DB Connector- Database connection (protected set)- Async versions of all database operations
Extends AsyncDataBaseStore with async bulk operations.
DataBaseStore<DB,T>- Base sync SQL storeDataBaseBulkStore<DB,T>- Base sync SQL bulk storeAsyncDataBaseStore<DB,T>- Base async SQL storeAsyncDataBaseBulkStore<DB,T>- Base async SQL bulk store
DataBaseRepository<T,S,DB>- SQL repository baseDataBaseBulkRepository<T,S,DB>- SQL bulk repositoryAsyncDataBaseRepository<T,S,DB>- Async SQL repositoryAsyncDataBaseBulkRepository<T,S,DB>- Async SQL bulk repository
CachedAsyncDataBaseBulkStore<DB,T>- Caching decorator for async bulk SQL storesSqlCacheKeyBuilder- Generates consistent cache keys from query parameters and filter expressionsSqlCacheOptions- Configuration for cache TTL, key prefix, and invalidation strategy- Automatic cache invalidation on write operations (Create, Update, Delete)
- Works with any
ICacheimplementation (MemoryCache, RedisCache, HybridCache)
Table(string name)- Maps entity class to a database tableNamedField(string? name)- Maps property to a column with a custom namePrimaryField- Marks primary key columnUniqueField- Marks column as uniqueIncrementField- Marks column as auto-incrementRequiredField- Forces NOT NULL even for nullable C# typesMaxLengthField(int maxLength)- Sets VARCHAR length for string fields (takes priority over PrecisionField)PrecisionField(int precision)- Sets numeric precisionScaleField(int scale)- Sets numeric scaleIgnoreField- Excludes a property from SQL field mapping (skipped during table creation and CRUD operations)
Standard DataAnnotations attributes are recognized alongside Birko attributes. Birko attributes take precedence when both are specified on the same property.
| DataAnnotation | Birko Equivalent | Notes |
|---|---|---|
[Table("name")] |
[Table("name")] |
From Schema namespace |
[Column("name")] |
[NamedField("name")] |
[NamedField] takes precedence if both present |
[Key] |
[PrimaryField] |
|
[Required] |
[RequiredField] |
|
[MaxLength(n)] |
[MaxLengthField(n)] |
Birko value takes precedence |
[StringLength(n)] |
[MaxLengthField(n)] |
Birko value takes precedence |
[DatabaseGenerated(Identity)] |
[IncrementField] |
From Schema namespace |
[NotMapped] |
[IgnoreField] |
From Schema namespace |
No DataAnnotations equivalent exists for [UniqueField], [PrecisionField], or [ScaleField].
ColumnModel- Represents a table columnTableModel- Represents a database table
SqlException- SQL-specific exceptionsConnectionException- Connection failure exceptionsQueryException- Query execution exceptions
- SQL helper extensions for common operations
SQL stores use a typed connector:
public abstract class DataBaseStore<DB, T> : AbstractStore<T>
where T : Models.Entity
where DB : class, IDisposable
{
protected DB Connector { get; protected set; }
protected override void Dispose(bool disposing)
{
if (disposing && Connector != null)
{
Connector.Dispose();
}
base.Dispose(disposing);
}
}using Birko.Data.SQL.Stores;
using System.Data.SqlClient;
public class CustomerStore : DataBaseStore<SqlConnection, Customer>, IStore<Customer>
{
public override Guid Create(Customer item)
{
var cmd = Connector.CreateCommand();
cmd.CommandText = "INSERT INTO Customers (Id, Name) VALUES (@Id, @Name)";
// Add parameters and execute
}
public override void Read(Customer item)
{
var cmd = Connector.CreateCommand();
cmd.CommandText = "SELECT * FROM Customers WHERE Id = @Id";
// Execute and populate item
}
}Base settings class for all SQL providers, extending RemoteSettings:
CommandTimeout(default: 30 seconds) — SQL command execution timeoutConnectionTimeout(default: 15 seconds) — connection attempt timeout- Abstract
GetConnectionString()— overridden by each SQL provider
Provider-specific settings extend SqlSettings:
MSSqlSettings—MultipleActiveResultSets,TrustServerCertificateMySqlSettings—BulkInsertBatchSizePostgreSqlSettings—UseBinaryImport
SQLite uses SqLiteSettings (extends PasswordSettings, not SqlSettings).
SQL stores still accept RemoteSettings / PasswordSettings via SetSettings(ISettings). The connector's CreateConnection checks for typed settings first and falls back to the legacy format.
Pass settings via base.SetSettings():
public override void SetSettings(Settings settings)
{
base.SetSettings(settings);
// Connector is created from settings
}- Birko.Data.Core, Birko.Data.Stores, Birko.Data.Repositories
- .NET 10.0
- Birko.Data.SQL.MSSql
- Birko.Data.SQL.PostgreSQL
- Birko.Data.SQL.MySQL
- Birko.Data.SQL.SqLite
- Birko.Data.TimescaleDB
- Birko.Data.SQL.View
Enum properties are automatically mapped to INTEGER fields. IntegerField handles read/write conversion via Enum.ToObject() and (int) cast. Both non-nullable and nullable enums are supported.
Properties decorated with [IgnoreField] are skipped by AbstractField.CreateAbstractField() — they won't be included in table creation or any CRUD operations. Unsupported property types also return null instead of throwing FieldAttributeException.
Always use protected set for the Connector property:
protected DB Connector { get; protected set; }Don't create settings inline - pass through base class:
// WRONG
var settings = new PasswordSettings { UserName = "...", Port = 123 };
// CORRECT
base.SetSettings(settings); // settings is passed from repositoryProvide a parameterless constructor in derived repositories:
public class MyRepository : DataBaseRepository<Entity, MyStore, SqlConnection>
{
public MyRepository() : base()
{
// Creates MyStore by default
}
}- See: Birko.Data.SQL.MSSql
- Connector:
SqlConnection - Namespace:
System.Data.SqlClient
- See: Birko.Data.SQL.PostgreSQL
- Connector:
NpgsqlConnection - Package:
Npgsql
- See: Birko.Data.SQL.MySQL
- Connector:
MySqlConnection - Package:
MySql.Data
- See: Birko.Data.SQL.SqLite
- Connector:
SqliteConnection - Package:
Microsoft.Data.Sqlite
- See: Birko.Data.TimescaleDB
- Based on PostgreSQL
- Connector:
NpgsqlConnection
When making changes that affect the public API, features, or usage patterns of this project, update the README.md accordingly. This includes:
- New classes, interfaces, or methods
- Changed dependencies
- New or modified usage examples
- Breaking changes
When making major changes to this project, update this CLAUDE.md to reflect:
- New or renamed files and components
- Changed architecture or patterns
- New dependencies or removed dependencies
- Updated interfaces or abstract class signatures
- New conventions or important notes
Every new public functionality must have corresponding unit tests. When adding new features:
- Create test classes in the corresponding test project
- Follow existing test patterns (xUnit + FluentAssertions)
- Test both success and failure cases
- Include edge cases and boundary conditions