Skip to main content
ClaudeWave
Skill64 estrellas del repoactualizado 22d ago

dotnet-sqlserver-best-practices

SQL Server database design best practices, naming conventions, indexing strategies, and performance optimization for .NET applications using Microsoft.Data.SqlClient and EF Core.

Instalar en Claude Code
Copiar
git clone --depth 1 https://github.com/ronnythedev/dotnet-clean-architecture-skills /tmp/dotnet-sqlserver-best-practices && cp -r /tmp/dotnet-sqlserver-best-practices/skills/25.2-dotnet-sqlserver-best-practices ~/.claude/skills/dotnet-sqlserver-best-practices
Después abre una sesión nueva de Claude Code; el skill carga automáticamente.

SKILL.md

# SQL Server Best Practices for .NET

## Overview

Best practices for SQL Server database design, naming conventions, indexing, and performance optimization when using with .NET and Entity Framework Core.

## Quick Reference

| Category | Best Practice |
|----------|---------------|
| **Naming** | PascalCase for tables/columns |
| **Primary Keys** | Use `uniqueidentifier` (Guid) with `NEWSEQUENTIALID()` or `int`/`bigint` IDENTITY |
| **Timestamps** | Use `datetimeoffset` with UTC |
| **Indexes** | Index foreign keys, unique constraints |
| **Strings** | Use `nvarchar(n)` with explicit lengths |
| **JSON** | Use `nvarchar(max)` with JSON functions (SQL Server 2016+) |

---

## Naming Conventions

### PascalCase Standard

SQL Server convention is **PascalCase** for all identifiers:

```sql
-- PascalCase (SQL Server convention)
CREATE TABLE UserProfiles (
    UserId uniqueidentifier PRIMARY KEY DEFAULT NEWSEQUENTIALID(),
    FirstName nvarchar(100) NOT NULL,
    LastName nvarchar(100) NOT NULL,
    CreatedAt datetimeoffset NOT NULL DEFAULT SYSUTCDATETIME(),
    UpdatedAt datetimeoffset NOT NULL DEFAULT SYSUTCDATETIME()
);
```

### EF Core Setup

```csharp
// src/{name}.infrastructure/DependencyInjection.cs
services.AddDbContext<ApplicationDbContext>(options =>
{
    options.UseSqlServer(connectionString);
    // EF Core uses PascalCase by default — matches SQL Server convention
});
```

### Naming Patterns

| Object | Pattern | Example |
|--------|---------|---------|
| Tables | `PascalCase` (plural) | `UserProfiles`, `OrderItems` |
| Columns | `PascalCase` | `FirstName`, `CreatedAt` |
| Primary Keys | `PK_{Table}` | `PK_Users`, `PK_Orders` |
| Foreign Keys | `FK_{Table}_{RefTable}` | `FK_Orders_Users` |
| Indexes | `IX_{Table}_{Column(s)}` | `IX_Users_Email` |
| Unique Indexes | `UIX_{Table}_{Column(s)}` | `UIX_Users_Email` |
| Check Constraints | `CK_{Table}_{Column}` | `CK_Users_Age` |
| Default Constraints | `DF_{Table}_{Column}` | `DF_Users_CreatedAt` |
| Schemas | `PascalCase` | `dbo`, `Sales`, `Identity` |

---

## Data Types

### Recommended Types

| C# Type | SQL Server Type | Notes |
|---------|-----------------|-------|
| `Guid` | `uniqueidentifier` | Use `NEWSEQUENTIALID()` to avoid index fragmentation |
| `string` | `nvarchar(n)` | Always specify length; Unicode by default |
| `string` (large) | `nvarchar(max)` | Only when > 4000 characters needed |
| `int` | `int` | 4 bytes, -2B to +2B |
| `long` | `bigint` | 8 bytes |
| `decimal` | `decimal(p,s)` | Exact precision for money |
| `double` | `float` | Floating point |
| `bool` | `bit` | 0/1 |
| `DateTime` | `datetimeoffset` | Always use with time zone |
| `DateTime` (date only) | `date` | When time is not needed |
| `byte[]` | `varbinary(max)` | Binary data |
| `byte[]` (concurrency) | `rowversion` | Auto-increment on update |

### nvarchar vs varchar

```sql
-- nvarchar: Unicode (2 bytes per char) - PREFERRED
CREATE TABLE Products (
    Id uniqueidentifier PRIMARY KEY,
    Name nvarchar(200) NOT NULL,        -- Supports international characters
    Description nvarchar(2000)
);

-- varchar: Non-Unicode (1 byte per char) - only for ASCII-only data
CREATE TABLE AuditLogs (
    Id bigint IDENTITY PRIMARY KEY,
    Action varchar(50) NOT NULL          -- Known ASCII values like 'INSERT', 'UPDATE'
);
```

**Always specify length:**
- `nvarchar(max)` can't be indexed and has performance implications
- Use the smallest length that fits the domain (email: 256, name: 100, etc.)

### Timestamps

```sql
-- datetimeoffset with UTC default
CreatedAt datetimeoffset NOT NULL CONSTRAINT DF_Users_CreatedAt DEFAULT SYSUTCDATETIME(),
UpdatedAt datetimeoffset NOT NULL CONSTRAINT DF_Users_UpdatedAt DEFAULT SYSUTCDATETIME()

-- datetime2 alternative (no timezone, but higher precision than datetime)
CreatedAt datetime2(7) NOT NULL DEFAULT SYSUTCDATETIME()

-- AVOID legacy datetime type
-- CreatedAt datetime NOT NULL  -- Lower precision, limited range
```

```csharp
// EF Core configuration
builder.Property(e => e.CreatedAt)
    .HasColumnType("datetimeoffset")
    .IsRequired()
    .HasDefaultValueSql("SYSUTCDATETIME()");
```

### JSON Support (SQL Server 2016+)

```sql
-- Store JSON in nvarchar(max)
CREATE TABLE Products (
    Id uniqueidentifier PRIMARY KEY,
    Metadata nvarchar(max) NULL,
    CONSTRAINT CK_Products_Metadata_JSON CHECK (ISJSON(Metadata) = 1)
);

-- Query JSON
SELECT Id, JSON_VALUE(Metadata, '$.category') AS Category
FROM Products
WHERE JSON_VALUE(Metadata, '$.isActive') = 'true';
```

```csharp
// EF Core configuration
builder.Property(e => e.Metadata)
    .HasColumnType("nvarchar(max)");

// EF Core 7+ owned types as JSON
builder.OwnsOne(e => e.Settings, settingsBuilder =>
{
    settingsBuilder.ToJson();
});
```

---

## Primary Keys

### Sequential GUID - Recommended

```sql
-- NEWSEQUENTIALID() avoids index fragmentation (page splits)
CREATE TABLE Users (
    Id uniqueidentifier PRIMARY KEY DEFAULT NEWSEQUENTIALID(),
    Email nvarchar(256) NOT NULL
);
```

```csharp
// EF Core - let SQL Server generate sequential GUIDs
builder.Property(e => e.Id)
    .HasDefaultValueSql("NEWSEQUENTIALID()");

// In domain entity - app generates (use sequential GUID library)
public static User Create(...)
{
    return new User(Guid.NewGuid(), ...);  // Or use RT.Comb for sequential
}
```

**Why NEWSEQUENTIALID() over NEWID()?**
- `NEWID()` generates random GUIDs causing clustered index fragmentation
- `NEWSEQUENTIALID()` generates sequential GUIDs for efficient inserts
- 16 bytes vs 4 bytes (int) — tradeoff for global uniqueness

### IDENTITY Alternative

```sql
-- Auto-increment (best for clustered index performance)
CREATE TABLE Orders (
    Id int IDENTITY(1,1) PRIMARY KEY,
    OrderNumber nvarchar(20) NOT NULL
);

-- bigint for high-volume tables
CREATE TABLE AuditLogs (
    Id bigint IDENTITY(1,1) PRIMARY KEY
);
```

```csharp
// EF Core
builder.Property(e => e.Id)
    .UseIdentityColumn();  // SQL Server IDENTITY
```

---

## Indexing Str
dotnet-clean-architectureSkill

Scaffolds a complete .NET solution following Clean Architecture principles with proper layer separation (API, Application, Domain, Infrastructure). Creates project structure, dependency injection setup, and cross-cutting concerns configuration.

dotnet-cqrs-command-generatorSkill

Generates CQRS Commands with Handlers, Validators, and Request DTOs following Clean Architecture patterns. Commands represent actions that modify state and return Result types for proper error handling.

dotnet-cqrs-query-generatorSkill

Generates CQRS Queries with Handlers and Response DTOs for read operations. Uses Dapper for optimized read queries, bypassing the domain model for better performance.

dotnet-domain-entity-generatorSkill

Generates Domain Entities following DDD principles with factory methods, private setters, domain events, and proper encapsulation. Supports aggregate roots, child entities, and value objects.

dotnet-repository-patternSkill

Generates Repository interfaces and implementations following the Repository pattern. Provides data access abstraction for aggregate roots with EF Core implementations.

dotnet-ef-core-configurationSkill

Generates Entity Framework Core configurations using Fluent API. Maps domain entities to database tables with proper relationships, constraints, and conventions.

dotnet-legacy-api-controllersSkill

Generates RESTful API Controllers with proper routing, versioning, authorization, and MediatR integration. Follows REST conventions and Clean Architecture patterns.

dotnet-minimal-api-endpointsSkill

Generates Minimal API endpoints following Microsoft's recommended approach. Creates fast, testable HTTP APIs with minimal code using MapGet/MapPost/MapPut/MapDelete. Preferred over controller-based APIs for new projects.