EFEF Core Handbook

TEMEL

Property (Sütun) Yapılandırması

C# property'lerinin veritabanındaki sütunlara nasıl dönüşeceğini kontrol eder: veri tipi, uzunluk, null olup olmayacağı, varsayılan değer, computed column gibi.

Veritabanı sağlayıcısı Bu sayfadaki eşleşen örnekleri seçilen sağlayıcıya göre gösterir.

Fluent API

// Zorunluluk
builder.Property(p => p.Name).IsRequired();
builder.Property(p => p.Description).IsRequired(false);  // nullable

// Maksimum uzunluk
builder.Property(p => p.Name).HasMaxLength(200);

// Sütun adı
builder.Property(p => p.Name).HasColumnName("ProductName");

// Sütun tipi
builder.Property(p => p.Price).HasColumnType("decimal(18,2)");
builder.Property(p => p.Description).HasColumnType("nvarchar(max)");

// Varsayılan değer
builder.Property(p => p.IsActive).HasDefaultValue(true);
builder.Property(p => p.CreatedAt).HasDefaultValueSql("GETUTCDATE()");

// Computed column (hesaplanmış sütun) — Virtual: diskte saklanmaz, her SELECT'te hesaplanır
builder.Property(p => p.FullName)
       .HasComputedColumnSql("[FirstName] + ' ' + [LastName]");

// Stored (Persisted) computed column — Diskte saklanır, INDEX konulabilir, sadece INSERT/UPDATE'te hesaplanır
builder.Property(p => p.FullName)
       .HasComputedColumnSql("[FirstName] + ' ' + [LastName]", stored: true);
// stored: false (varsayılan) → SQL: AS ([FirstName] + ' ' + [LastName])
// stored: true             → SQL: AS ([FirstName] + ' ' + [LastName]) PERSISTED
// 💡 Sık WHERE/ORDER BY'da kullanılacaksa → stored: true + index oluştur

// Unicode
builder.Property(p => p.Name).IsUnicode(true);   // nvarchar
builder.Property(p => p.Code).IsUnicode(false);  // varchar

// Sütun sırası (EF Core 7+)
builder.Property(p => p.Name).HasColumnOrder(1);

// Sütun yorum (comment)
builder.Property(p => p.Price).HasComment("KDV dahil fiyat");

// Ignore — property'yi veritabanına MAP ETME (sütun oluşmaz)
builder.Ignore(p => p.DisplayPrice);      // Sadece UI'da kullanılan hesaplanmış alan
builder.Ignore(p => p.IsInStock);         // Başka servisten gelen runtime değer
// Ne zaman kullanılır?
// - Property sadece uygulama katmanında anlam taşıyorsa (NotMapped alternatifi)
// - Backing field olmayan computed property'ler
// - Serializasyon/DTO amaçlı property'ler (ör: FullAddress = City + " " + District)
// [NotMapped] attribute ile aynı iş — ama Fluent API'de yapılır

// Precision & Scale (decimal için kısayol)
builder.Property(p => p.Price).HasPrecision(18, 2);

// 🆕 EF Core 10 (GA — .NET 10): Custom Default Constraint adları
builder.Property(p => p.CreatedAt)
       .HasDefaultValueSql("GETUTCDATE()", "DF_Products_CreatedAt");  // İkinci parametre: constraint adı

// Tüm default constraint'lere otomatik isim ver:
modelBuilder.UseNamedDefaultConstraints();  // SQL Server
// ⚠️ Mevcut migration'larınız varsa, bir sonraki migration TÜM constraint'leri rename eder!

Tam bir örnek — C# entity'si ve karşılık gelen SQL:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Code { get; set; }
    public decimal Price { get; set; }
    public string Description { get; set; }
    public bool IsActive { get; set; }
    public DateTime CreatedAt { get; set; }
    public string FullName { get; set; }  // computed: FirstName + ' ' + LastName
}
CREATE TABLE [catalog].[Products] (
    [Id]          INT            IDENTITY(1,1) NOT NULL,
    [ProductName] NVARCHAR(200)  NOT NULL,                          -- HasColumnName + IsRequired + HasMaxLength
    [Code]        VARCHAR(50)    NOT NULL,                           -- IsUnicode(false)
    [Price]       DECIMAL(18,2)  NOT NULL,                          -- HasPrecision(18,2)
    [Description] NVARCHAR(MAX)  NULL,                              -- IsRequired(false) + nvarchar(max)
    [IsActive]    BIT            NOT NULL DEFAULT 1,                -- HasDefaultValue(true)
    [CreatedAt]   DATETIME2      NOT NULL DEFAULT GETUTCDATE(),     -- HasDefaultValueSql
    [FullName] AS ([FirstName] + ' ' + [LastName]) PERSISTED,       -- HasComputedColumnSql(..., stored: true)
    
    CONSTRAINT [PK_Products] PRIMARY KEY CLUSTERED ([Id])
);

-- Sütun yorumu
EXEC sp_addextendedproperty 
    @name = N'MS_Description', @value = N'KDV dahil fiyat',
    @level1type = N'TABLE', @level1name = 'Products',
    @level2type = N'COLUMN', @level2name = 'Price';
CREATE TABLE products (
    id           INT GENERATED ALWAYS AS IDENTITY,
    product_name VARCHAR(200)   NOT NULL,
    code         VARCHAR(50)    NOT NULL,                         -- unicode/non-unicode farkı yok
    price        NUMERIC(18,2)  NOT NULL,
    description  TEXT           NULL,                             -- sınırsız text
    is_active    BOOLEAN        NOT NULL DEFAULT TRUE,            -- BIT değil BOOLEAN!
    created_at   TIMESTAMPTZ    NOT NULL DEFAULT (NOW() AT TIME ZONE 'UTC'),
    full_name    TEXT GENERATED ALWAYS AS (first_name || ' ' || last_name) STORED,
    CONSTRAINT pk_products PRIMARY KEY (id)
);

COMMENT ON COLUMN products.price IS 'KDV dahil fiyat';
// PostgreSQL property yapılandırma farkları
builder.Property(p => p.CreatedAt)
       .HasDefaultValueSql("NOW() AT TIME ZONE 'UTC'");  // GETUTCDATE() yerine

builder.Property(p => p.FullName)
       .HasComputedColumnSql("first_name || ' ' || last_name", stored: true);
       // SQL Server: [FirstName] + ' ' + [LastName]
       // PostgreSQL: first_name || ' ' || last_name  (|| = concat)

builder.Property(p => p.Description)
       .HasColumnType("text");  // nvarchar(max) yerine TEXT kullan

Örnek veri — tabloda nasıl görünür:

Id ProductName Code Price Description IsActive CreatedAt FullName
1 MacBook Pro MBP-16 84999.99 Apple M3 Pro çipli... 1 2025-01-15 08:30:00 MacBook Pro 16
2 iPhone 15 IPH-15 54999.00 NULL 1 2025-01-16 10:00:00 iPhone 15 Pro
3 AirPods Max APM-01 12999.50 Kablosuz kulaklık 0 2025-02-01 14:20:00 AirPods Max

PostgreSQL tip eşlemeleri:

C# / EF SQL Server PostgreSQL
bool BIT BOOLEAN
DateTime DATETIME2 TIMESTAMP
DateTimeOffset DATETIMEOFFSET TIMESTAMPTZ
string (max) NVARCHAR(MAX) TEXT
decimal DECIMAL(p,s) NUMERIC(p,s)
byte[] VARBINARY(MAX) BYTEA
Guid UNIQUEIDENTIFIER UUID
TimeSpan TIME INTERVAL