Visor.SqlServer 1.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package Visor.SqlServer --version 1.1.0
                    
NuGet\Install-Package Visor.SqlServer -Version 1.1.0
                    
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="Visor.SqlServer" Version="1.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Visor.SqlServer" Version="1.1.0" />
                    
Directory.Packages.props
<PackageReference Include="Visor.SqlServer" />
                    
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 Visor.SqlServer --version 1.1.0
                    
#r "nuget: Visor.SqlServer, 1.1.0"
                    
#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 Visor.SqlServer@1.1.0
                    
#: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=Visor.SqlServer&version=1.1.0
                    
Install as a Cake Addin
#tool nuget:?package=Visor.SqlServer&version=1.1.0
                    
Install as a Cake Tool

Visor

Visor Logo Placeholder

High-performance, Source-Generated ORM for .NET 10+. Treats your Database Stored Procedures as a strictly typed API.

License: MIT Platform Build Status

Visor is designed to solve the "Enterprise Gap" in .NET data access:

  • Dapper is fast but type-unsafe and requires boilerplate.
  • EF Core is convenient but heavy and slow for bulk operations.
  • Visor uses Source Generators to write zero-allocation ADO.NET code for you at compile time. Visor automates TVP boilerplate that you usually write manually.

πŸš€ Benchmarks: The "10k Insert" Challenge

We compared inserting 10,000 records into MS SQL Server using a Transactional Stored Procedure with Table-Valued Parameters (TVP).

Method Operation Time (Mean) Memory Allocated GC Gen0/1/2
Visor (TVP) Streaming 51.82 ms 1.07 MB 0 / 0 / 0
EF Core 10 Bulk Insert 517.73 ms 65.04 MB 8 / 3 / 1
Dapper Loop Insert 43,069.73 ms 15.34 MB 1 / 0 / 0

Why is Visor 10x faster than EF and 800x faster than loops?

  • Zero Allocation Streaming: Visor maps List<T> directly to IEnumerable<SqlDataRecord> (MSSQL) or Arrays (Postgres) using yield return. No intermediate DataTable or memory copying.
  • No Runtime Reflection: All mapping code is generated at compile-time.
  • Strict Mapping: If your DB schema changes, Visor fails fast with clear exceptions, not silent data corruption.

πŸ“¦ Installation

dotnet add package Visor.Core
dotnet add package Visor.Generators

# Choose your provider:
dotnet add package Visor.SqlServer
# OR
dotnet add package Visor.PostgreSql

⚑ Quick Start (MSSQL)

1. Define your Data Contract

Describe your Stored Procedure as a C# interface.

using Visor.Abstractions;

[Visor(VisorProvider.SqlServer)]
public interface IUserRepository
{
    // 1. Simple Execute (Scalar)
    [Endpoint("sp_GetUserCount")]
    Task<int> GetCountAsync();

    // 2. Read Data (DTO Mapping)
    [Endpoint("sp_GetUserById")]
    Task<UserDto> GetUserAsync(int id);

    // 3. High-Performance Bulk Insert (TVP)
    [Endpoint("sp_ImportUsers")]
    Task ImportUsersAsync(List<UserItemDto> users);
}

2. Define your DTOs

Use [VisorMsSqlColumn] for strict SQL type mapping.

using Visor.SqlServer; // Provider-specific attributes

[VisorTable("dbo.UserListType")] // Matches SQL User-Defined Type
public class UserItemDto
{
    [VisorMsSqlColumn(0, System.Data.SqlDbType.Int)]
    public int Id { get; set; }

    [VisorMsSqlColumn(1, System.Data.SqlDbType.NVarChar, 100)]
    public string Name { get; set; }
}

3. Register & Use

Visor generates the implementation class UserRepository automatically.

// In Program.cs
services.AddScoped<IVisorConnectionFactory>(sp => 
    new SqlServerConnectionFactory("Server=..."));
services.AddScoped<IUserRepository, UserRepository>();

// In your Service
public class MyService(IUserRepository repo)
{
    public async Task SyncUsers(List<UserItemDto> users)
    {
        // This executes with Zero Allocation!
        await repo.ImportUsersAsync(users);
    }
}

🐘 PostgreSQL Support

Visor fully supports PostgreSQL via Npgsql. It maps List<T> parameters to PostgreSQL Arrays/Composite Types automatically.

1. Define Interface

Specify the provider in the attribute:

[Visor(VisorProvider.PostgreSql)] // <--- Switch to Postgres
public interface IPgUserRepo
{
    [Endpoint("sp_import_users")]
    Task ImportUsersAsync(List<PgUserItem> users);
}

2. Configure Bootstrapper (Important!)

PostgreSQL requires composite types to be registered at startup. Visor generates a helper method for this.

// In Program.cs
var dataSourceBuilder = new NpgsqlDataSourceBuilder("Host=...");

// This method is AUTO-GENERATED by Visor! 
// It registers all types marked with [VisorTable].
dataSourceBuilder.UseVisor(); 

var dataSource = dataSourceBuilder.Build();

services.AddScoped<IVisorConnectionFactory>(sp => 
    new PostgreSqlConnectionFactory(dataSource));

3. Define DTO

Use [VisorColumn] with Name property to map C# PascalCase to Postgres snake_case. Types are inferred automatically.

[VisorTable("user_list_type")]
public class PgUserItem
{
    [VisorColumn(0, Name = "id")] 
    public int Id { get; set; }

    [VisorColumn(1, Name = "user_name")]
    public string UserName { get; set; }
}

πŸ›‘οΈ Transaction Support

Visor supports explicit transactions via the VisorDbLease pattern (Unit of Work).

public async Task CreateOrderFlow(OrderDto order)
{
    // Start a transaction scope (scoped per request)
    await _factory.BeginTransactionAsync();

    try 
    {
        // These repositories will automatically share the active transaction
        await _orders.CreateAsync(order);
        await _inventory.DecreaseStockAsync(order.ProductId, order.Quantity);

        await _factory.CommitTransactionAsync();
    }
    catch
    {
        await _factory.RollbackTransactionAsync();
        throw;
    }
}

🧠 Philosophy: The "White Box" Approach

Most ORMs are "Black Boxes" β€” they do magic at runtime that you can't see or debug easily. Visor is a "White Box".

  • It generates readable C# code in your obj/Generated folder.
  • You can step through the generated code with a debugger.
  • You can see exactly how SqlDataReader or NpgsqlDataReader is being read.
  • Strict by Default: If a column is missing in the result set, Visor throws a VisorMappingException immediately, preventing "silent zero" bugs in production.

πŸ—ΊοΈ Roadmap

  • MSSQL Support (Complete)
  • TVP Streaming (Complete)
  • PostgreSQL Support (Complete)
  • Transactions (Complete)
  • NuGet Packaging
  • CLI Tool for Database-First scaffolding

License

Distributed under the MIT License. See LICENSE for more information.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  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
1.2.0 666 12/1/2025
1.1.2 180 11/25/2025
1.1.1 175 11/24/2025
1.1.0 180 11/24/2025