İLERİ
Complex Types — EF Core 8+
Owned Entity'nin modern alternatifi. Kimliği (Id) olmayan, birden fazla entity'de tekrar kullanabileceğin değer nesneleri tanımlar. Para birimi, koordinat, renk gibi yapılar için.
Veritabanı sağlayıcısı
Bu sayfadaki eşleşen örnekleri seçilen sağlayıcıya göre gösterir.
Gerçek Senaryo: Ürün fiyatı — para birimi ile birlikte
decimal Price yazmak yetmez — hangi para birimi? Money tipini hem Product hem Order hem başka entityler kullanabilir.
// --- Tipler ---
public record Money(decimal Amount, string Currency); // record → immutable
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public Money Price { get; set; } // satış fiyatı
public Money CostPrice { get; set; } // maliyet fiyatı
}
public class Order
{
public int Id { get; set; }
public Money Total { get; set; } // aynı Money tipi burada da kullanılıyor
}
// --- Config ---
public class ProductConfiguration : IEntityTypeConfiguration<Product>
{
public void Configure(EntityTypeBuilder<Product> builder)
{
builder.ToTable("Products");
builder.HasKey(p => p.Id);
builder.Property(p => p.Name).IsRequired().HasMaxLength(200);
builder.ComplexProperty(p => p.Price, price =>
{
price.Property(m => m.Amount) .HasColumnName("Price_Amount") .HasPrecision(18, 2);
price.Property(m => m.Currency).HasColumnName("Price_Currency").HasMaxLength(3);
});
builder.ComplexProperty(p => p.CostPrice, cost =>
{
cost.Property(m => m.Amount) .HasColumnName("Cost_Amount") .HasPrecision(18, 2);
cost.Property(m => m.Currency).HasColumnName("Cost_Currency").HasMaxLength(3);
});
}
}
Oluşan SQL:
CREATE TABLE [Products] (
[Id] INT IDENTITY(1,1) NOT NULL,
[Name] NVARCHAR(200) NOT NULL,
[Price_Amount] DECIMAL(18,2) NOT NULL,
[Price_Currency] NVARCHAR(3) NOT NULL,
[Cost_Amount] DECIMAL(18,2) NOT NULL,
[Cost_Currency] NVARCHAR(3) NOT NULL,
CONSTRAINT [PK_Products] PRIMARY KEY CLUSTERED ([Id])
);
CREATE TABLE products (
id INT GENERATED BY DEFAULT AS IDENTITY,
name VARCHAR(200) NOT NULL,
price_amount NUMERIC(18,2) NOT NULL,
price_currency VARCHAR(3) NOT NULL,
cost_amount NUMERIC(18,2) NOT NULL,
cost_currency VARCHAR(3) NOT NULL,
CONSTRAINT pk_products PRIMARY KEY (id)
);
Örnek veri:
| Id | Name | Price_Amount | Price_Currency | Cost_Amount | Cost_Currency |
|---|---|---|---|---|---|
| 1 | Laptop | 84999.99 | TRY | 62000.00 | TRY |
| 2 | iPhone | 54999.00 | TRY | 41000.00 | TRY |
| 3 | AirPods | 299.00 | USD | 180.00 | USD |
Kullanımda:
var product = new Product
{
Name = "Laptop",
Price = new Money(25000, "TRY"),
CostPrice = new Money(18000, "TRY")
};
// LINQ sorgusu — EF SQL'e çevirir
var pahalılar = context.Products
.Where(p => p.Price.Amount > 10000 && p.Price.Currency == "TRY")
.ToList();
-- EF'in ürettiği SQL:
SELECT [p].[Id], [p].[Name], [p].[Price_Amount], [p].[Price_Currency],
[p].[Cost_Amount], [p].[Cost_Currency]
FROM [Products] AS [p]
WHERE [p].[Price_Amount] > 10000.0 AND [p].[Price_Currency] = N'TRY';
-- EF'in ürettiği SQL:
SELECT p.id, p.name, p.price_amount, p.price_currency,
p.cost_amount, p.cost_currency
FROM products AS p
WHERE p.price_amount > 10000.0 AND p.price_currency = 'TRY';
Owned Entity ile Complex Type farkı
| Owned Entity | Complex Type (EF8+) | |
|---|---|---|
| Ayrı tabloya taşınabilir mi? | ToTable(...) |
|
| JSON'a map edilebilir mi? | ToJson() |
EF Core 10+ 🆕 |
| Koleksiyon olabilir mi? | OwnsMany |
(JSON içinde EF10) |
| Struct kullanılabilir mi? | EF Core 10+ 🆕 | |
| Optional olabilir mi? | EF Core 10+ 🆕 | |
| ExecuteUpdate desteği | EF Core 10+ 🆕 | |
| Semantik | Kimliksiz entity gibi davranır | Gerçek value object |
| Ne zaman tercih et | Legacy, koleksiyon / ayrı tablo gerekiyorsa | Yeni projelerde her zaman tercih et (EF10 ile tam destek) |
🆕 EF Core 10 ile Complex Types artık tavsiye edilen yaklaşım:
- JSON mapping (
b.ComplexProperty(c => c.Address, c => c.ToJson()))- Struct desteği (identity olmayan value object'ler için doğal)
- Optional complex types (
Address?)ExecuteUpdateAsyncile bulk güncelleme- Owned entity'lerdeki "aynı referans atama" sorunu yok (value semantics)