Codebelt

Cuemon.Data.SqlClient

SQL Server specific data access primitives for executing DataStatement objects, building safe IN clauses, and generating T-SQL.

.NET 10.0 / .NET 9.0 MIT v10.5.3 36,901 downloads

Overview

Cuemon.Data.SqlClient extends Cuemon.Data with Microsoft SQL Server specific building blocks. It gives consumers a SqlDataManager that executes DataStatement objects through Microsoft.Data.SqlClient, plus SQL Server aware helpers for safe IN clauses and generated T-SQL.

When an application already uses the repository's data abstractions, this package is the point where those abstractions become SQL Server aware. The manager can optionally wrap command execution in transient fault handling, while SqlInOperator<T> and SqlQueryBuilder cover the common cases where callers need parameter-safe filtering or repeatable CRUD query text.

Key APIs

SqlDataManager is the SQL Server implementation of DataManager. It builds SqlCommand instances from DataStatement, applies the configured connection string, copies parameters and timeout values, and then uses the inherited execute surface for readers, scalars, existence checks, and non-query commands.

TransientFaultHandlingOptionsCallback lets a SqlDataManager wrap command execution in Cuemon.Resilience.TransientOperation. The default callback enables recovery and treats a fixed set of SQL Server and Azure SQL error numbers, plus timeout-related messages, as retryable failures.

ExecuteIdentityInt32 appends SELECT CONVERT(INT, SCOPE_IDENTITY()) to a text command and preserves the original statement parameters, timeout, and command type. It is the typed helper for inserts where the generated key fits in an int.

ExecuteIdentityInt64 follows the same pattern but converts SCOPE_IDENTITY() to BIGINT. Use it when the table identity exceeds the int range or the calling code standardizes on long.

ExecuteIdentityDecimal returns SCOPE_IDENTITY() as decimal and keeps the same text-only guard as the other identity helpers. That matches SQL Server flows where the caller wants the raw numeric shape before narrowing or mapping it.

SqlInOperator<T> specializes InOperator<T> for SQL Server by turning each value into a SqlParameter. Its inherited ToSafeResult flow gives consumers both the placeholder list and the matching parameter collection for an IN (...) clause.

SqlQueryBuilder specializes QueryBuilder for SQL Server CRUD and existence statements. Its GetQuery implementation understands square-bracket name encapsulation, TOP limits, WITH(NOLOCK) on reads, and SQL Server flavored INSERT, UPDATE, DELETE, SELECT, and SELECT 1 generation.

Basic usage

using System.Linq;
using Cuemon.Data;
using Cuemon.Data.SqlClient;
using Codebelt.Extensions.Xunit;
using Microsoft.Data.SqlClient;
using Xunit;

namespace Contoso.Data.Tests;

public class SqlInOperatorTest : Test
{
    public SqlInOperatorTest(ITestOutputHelper output) : base(output)
    {
    }

    [Fact]
    public void ShouldCreateParameterizedInClauseForSqlServer()
    {
        InOperatorResult result = new SqlInOperator<string>().ToSafeResult("A", "B", "C");
        var statement = new DataStatement(
            $"SELECT * FROM [Production].[ProductInventory] WHERE Shelf IN ({result})",
            o => o.Parameters = result.ToParametersArray());

        TestOutput.WriteLine(statement.Text);
        TestOutput.WriteLine(string.Join(", ", result.Arguments));

        Assert.Equal(result.Arguments, statement.Parameters.Select(p => p.ParameterName));
        Assert.All(statement.Parameters, p => Assert.IsType<SqlParameter>(p));
    }
}

Use this pattern when a SQL Server query needs an IN clause built from application values without concatenating raw literals into the command text. It matters because SqlInOperator<T> keeps the placeholder list and the generated SqlParameter instances aligned before the statement is handed to SqlDataManager.

Installation

dotnet add package Cuemon.Data.SqlClient

Usage guidance

Adopt this package when your code already uses DataStatement and DataManager style abstractions but needs SQL Server specific execution, identity retrieval helpers, safe IN clause parameterization, or repeatable T-SQL generation. If you only need a few hand-written SqlCommand calls and none of the DataManager, InOperator, or QueryBuilder abstractions, plain Microsoft.Data.SqlClient is the simpler choice.

Family packages