SharpPersistence 0.0.4

There is a newer version of this package available.
See the version list below for details.
dotnet add package SharpPersistence --version 0.0.4
                    
NuGet\Install-Package SharpPersistence -Version 0.0.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SharpPersistence" Version="0.0.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SharpPersistence" Version="0.0.4" />
                    
Directory.Packages.props
<PackageReference Include="SharpPersistence" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SharpPersistence --version 0.0.4
                    
#r "nuget: SharpPersistence, 0.0.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package SharpPersistence@0.0.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SharpPersistence&version=0.0.4
                    
Install as a Cake Addin
#tool nuget:?package=SharpPersistence&version=0.0.4
                    
Install as a Cake Tool
Branch Status
main Dotnet 9

SharpPersistence

SharpPersistence is a collection of robust, extensible, and thoroughly tested .NET libraries for working with database systems.

Installation

To install the packages, run the following commands:

dotnet add package SharpPersistence.Abstractions
dotnet add package SharpPersistence
dotnet add package SharpPersistence.EfCore

Or visit:

Features

SqlParser

  • SqlParser is available in SharpPersistence
  • Separation of Concerns: Keep complex SQL queries in .sql files instead of cluttering your C# code
  • Better SQL Editing: Full syntax highlighting, IntelliSense, and formatting in SQL files
  • Version Control Friendly: Track SQL changes separately from business logic
  • Team Collaboration: Database developers can work on SQL files while C# developers focus on application logic
  • Compile-Time Safety: Parse and validate SQL files at application startup, catching errors early
Basic Usage

1. Create SQL files with tagged blocks:

  • SQL statements must be enclosed by -- #start# TagName and -- #end# TagName comments.
  • Unique tag of a sql statement is case-insensitive.
-- #start# GetAllUsers
SELECT u.Id, u.Name, u.Email, u.CreatedAt
FROM Users u
WHERE u.Id = :userId
ORDER BY u.Name
-- #end# GetAllUsers

-- #start# GetActiveUsers
SELECT u.Id, u.Name, u.Email
FROM Users u
WHERE u.IsActive = 1 AND u.IsDeleted = 0
ORDER BY u.LastLoginDate DESC
-- #end# GetActiveUsers

2. Configure your project to copy SQL files:

  • Add this to your .csproj file's Project node to automatically copy SQL files to the output directory.
  • sharp_persistence_sql_files is the default directory. If you want to change it, make sure to pass the new value in the ParseFromStorage() method's parameter. The same value must be used in the TargetPath below.

<PropertyGroup>
    <DefaultItemExcludes>
        $(DefaultItemExcludes);out/**;publish/**;bin/**;obj/**
    </DefaultItemExcludes>
</PropertyGroup>

<ItemGroup>
<Content Include="**\*.sql"
         Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)"
         CopyToOutputDirectory="PreserveNewest"
         TargetPath="sharp_persistence_sql_files\%(RecursiveDir)\%(Filename)%(Extension)"/>
</ItemGroup>
  • Don't miss out the Project node during pasting the code. An example is given below:

<Project Sdk="Microsoft.NET.Sdk">
    
</Project>

3. Parse and use in your application:

// Parse SQL files at startup
IParsedSqlStorage parsedSqlStorage = new SqlParser().ParseFromStorage();

// Access parsed SQL by tag name (case-insensitive) through C# indexer
string getAllUsersQuery = parsedSqlStorage["GetAllUsers"];
// Use the query...

// Safe access with TryGet
if (parsedSqlStorage.TryGetParsedSql("GetAllUsers", out string? query))
{
    // Use the query...
}

4. Dependency Injection (ASP.NET Core):

// In Program.cs
IParsedSqlStorage parsedSqlStatements = new SqlParser().ParseFromStorage();
builder.Services.AddSingleton<IParsedSqlStorage>(parsedSqlStatements);

// In your service classes
public class UserService
{
    private readonly IDbConnectionFactory _dbConnectionFactory;
    private readonly IParsedSqlStorage _parsedSqlStorage;

    public UserService(IDbConnectionFactory dbConnectionFactory, IParsedSqlStorage sqlStorage)
    {
        _dbConnectionFactory = dbConnectionFactory;
        _parsedSqlStorage = parsedSqlStorage;
    }

    public async Task<IEnumerable<User>> GetAllUsersAsync(int userId, CancellationToken ct)
    {
        var sql = _parsedSqlStorage["GetAllUsers"];
        
        await using var connection = await _dbConnectionFactory.CreateConnectionAsync(ct);
        
        var parameters = new { userId };

        return await connection.QueryAsync<User>(new CommandDefinition(sql, parameters,
            cancellationToken: ct));
    }
}

Notes: SqlParser validates your SQL files at startup and throws detailed error messages for:

  • Missing start/end tags
  • Duplicate tag names
  • Invalid tag formats

SqlCheckConstrainGenerator

  • SqlCheckConstrainGenerator is available in SharpPersistence
  • Type-safe, raw SQL check constraint generation
  • Supports multiple RDBMS (SQL Server, PostgreSQL, MySQL)
  • Naming convention support (PascalCase, lower_snake_case, UPPER_SNAKE_CASE)
  • Handles all SQL comparison, logical, and set operators
  • Proper string escaping and identifier delimiting
  • Fully tested for edge cases and all method combinations

Some examples with IEntityTypeConfiguration of Ef Core are given below:

  var cc = new SqlCheckConstrainGenerator(Rdbms.PostgreSql, SqlNamingConvention.LowerSnakeCase, 
      delimitStringGlobalLevel: false);

  builder.ToTable(x => x.HasCheckConstraint(
      "valid_product_sell_price_in_sales_invoice",
      cc.GreaterThanOrEqual(nameof(SalesInvoiceItem.SingleUnitSellPrice),
          0, SqlDataType.Decimal)
  ));
  
  builder.ToTable(x => x.HasCheckConstraint(
    "valid_employee_release_data",
    cc.Or(
        cc.And(
            cc.EqualTo(nameof(EmploymentRecord.IsReleased), true),
            cc.IsNotNull(nameof(EmploymentRecord.ReleaseDate)),
            cc.IsNotNull(nameof(EmploymentRecord.ReleaseReasonId))
        ),
        cc.And(
            cc.EqualTo(nameof(EmploymentRecord.IsReleased), false),
            cc.IsNull(nameof(EmploymentRecord.ReleaseDate)),
            cc.IsNull(nameof(EmploymentRecord.ReleaseReasonId))
        )
    )
));
  
  builder.ToTable(x => x.HasCheckConstraint(
    "valid_debit_credit_entry",
    cc.Or(
        cc.And(
            cc.GreaterThanOrEqual(nameof(JournalVoucherItem.CreditAmount),
                0, SqlDataType.Decimal),
            cc.EqualTo(nameof(JournalVoucherItem.DebitAmount),
                0, SqlDataType.Decimal)
        ),
        cc.And(
            cc.GreaterThanOrEqual(nameof(JournalVoucherItem.DebitAmount),
                0, SqlDataType.Decimal),
            cc.EqualTo(nameof(JournalVoucherItem.CreditAmount),
                0, SqlDataType.Decimal)
        )
    )
));

RepositoryBase with IRepositoryBase

  • IRepositoryBase is available in SharpPersistence.Abstractions
  • RepositoryBase is available in SharpPersistence.EfCore
  • All CRUD operations with async support
  • Multiple overloads for flexible querying
  • Proper EF Core tracking management
  • Dependency injection ready
  • Readable, maintainable, and well-formatted code

UnitOfWork with IUnitOfWork

  • IUnitOfWork is available in SharpPersistence.Abstractions
  • UnitOfWork is available in SharpPersistence.EfCore
  • Transactional management of multiple repository operations
  • Ensures atomicity and consistency across changes
  • Integrates seamlessly with the repository pattern
  • Simplifies commit/rollback logic in service layers

Testing

  • All features are covered by xUnit v3 and Shouldly assertions.
  • Tests cover all overloads, edge cases, and RDBMS/naming convention combinations.
  • To run tests:
    dotnet test
    

Contributing

Contributions are welcome! Please open issues or submit pull requests for bug fixes, improvements, or new features.

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
0.0.8 31 9/15/2025
0.0.7 67 9/12/2025
0.0.6 198 6/27/2025
0.0.4 289 6/10/2025
0.0.3 148 6/4/2025
0.0.2 155 5/29/2025
0.0.1 154 5/29/2025