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 |