Neler yeni

Yazılım Forum

Tüm özelliklerimize erişmek için şimdi bize katılın. Kayıt olduktan ve giriş yaptıktan sonra konu oluşturabilecek, mevcut konulara yanıt gönderebilecek, itibar kazanabilecek, özel mesajlaşmaya erişebilecek ve çok daha fazlasını yapabileceksiniz! Bu hizmetlerimiz ise tamamen ücretsiz ve kurallara uyulduğu sürece sınırsızdır, o zaman ne bekliyorsunuz? Hadi, sizde aramıza katılın!

Entity Framework Core'da İleri Seviye Tekniklerle Uygulama Performansını Artırma ve Gelişmiş Modelleme

Giriş: Entity Framework Core ve İleri Seviye Geliştirme İhtiyacı

Entity Framework Core (EF Core), .NET uygulamalarında veritabanı işlemlerini kolaylaştıran güçlü bir Object-Relational Mapper (ORM) aracıdır. Geliştiricilerin veritabanı etkileşimlerini nesne odaklı bir yaklaşımla gerçekleştirmesini sağlayarak, tekrarlayan SQL yazma yükünü azaltır ve geliştirme hızını artırır. Ancak büyük ölçekli, yüksek performans gerektiren veya karmaşık veri yapılarına sahip projelerde, EF Core'un sunduğu temel özelliklerin ötesine geçmek gerekebilir. Bu tür senaryolarda, ileri seviye EF Core teknikleri devreye girer. Bu teknikler, uygulamanızın performansını optimize etmek, veri bütünlüğünü sağlamak, karmaşık modelleri daha etkin bir şekilde yönetmek ve EF Core'u projenizin özel ihtiyaçlarına göre genişletmek için kritik öneme sahiptir. Bu makalede, EF Core'un ileri seviye özelliklerini derinlemesine inceleyecek ve uygulamalarınızda nasıl daha verimli kullanabileceğinizi adım adım ele alacağız.

Performans Optimizasyonları: Sorgu Hızını ve Veri Yükünü Yönetme

Uygulama performansının temel taşlarından biri, veritabanı sorgularının ne kadar hızlı ve verimli çalıştığıdır. EF Core, bu konuda bize çeşitli optimizasyon araçları sunar.

  • Değişiklik Takibi Yönetimi (Change Tracking)
  • Sorgu Bölme (Query Splitting)
  • Derlenmiş Sorgular (Compiled Queries)
  • Yükleme Stratejileri (Eager, Explicit, Lazy Loading)

1. Değişiklik Takibi Yönetimi (AsNoTracking())

EF Core, sorgulanan varlıkların durumunu takip ederek, bu varlıklar üzerinde yapılan değişikliklerin
Kod:
SaveChanges()
metodu çağrıldığında otomatik olarak veritabanına yansıtılmasını sağlar. Ancak, eğer bir varlığı sadece okuma amaçlı kullanıyorsanız ve üzerinde herhangi bir güncelleme yapmayacaksanız, değişiklik takibi performans maliyeti yaratır.
Kod:
AsNoTracking()
metodu, EF Core'a bu varlıkları takip etmemesini söyleyerek bellek kullanımını ve CPU yükünü azaltır.

Kod:
using Microsoft.EntityFrameworkCore;

// Kullanıcıları sadece listelemek için AsNoTracking kullanın
var users = await _dbContext.Users.AsNoTracking().ToListAsync();

// Eğer güncelleme yapılacaksa AsNoTracking kullanmaktan kaçının
var userToUpdate = await _dbContext.Users.FirstOrDefaultAsync(u => u.Id == 1);
userToUpdate.Name = "Yeni Ad";
await _dbContext.SaveChangesAsync();

2. Sorgu Bölme (Query Splitting)

Tek bir sorguda birden fazla
Kod:
Include()
veya
Kod:
ThenInclude()
kullandığınızda, EF Core varsayılan olarak tüm ilgili verileri tek bir JOIN sorgusu ile getirmeye çalışır. Bu durum, özellikle çoklu seviyeli ilişkilerde ve büyük veri setlerinde kartesyen çarpımı problemine yol açarak sorgu performansını ciddi şekilde düşürebilir.
Kod:
AsSplitQuery()
metodu, EF Core'a bu sorguyu birden fazla ayrı sorguya bölmesini söyleyerek, her bir
Kod:
Include()
için ayrı bir sorgu gönderir ve sonuçları bellekte birleştirir. Bu, veritabanı tarafındaki yükü azaltır ve daha yönetilebilir sonuç setleri sağlar.

Kod:
var orders = await _dbContext.Orders
    .Include(o => o.OrderItems)
        .ThenInclude(oi => oi.Product)
    .AsSplitQuery() // Sorguyu birden fazla SQL sorgusuna böler
    .ToListAsync();

3. Derlenmiş Sorgular (Compiled Queries)

Tekrarlayan sorguları önbelleğe almak ve derlemek, sorgu oluşturma sürecinin getirdiği ek yükü ortadan kaldırır. EF Core, sorguyu ilk çalıştırdığında bir ifade ağacı oluşturur, bu ağacı SQL'e çevirir ve ardından bu SQL'i veritabanında çalıştırır. Derlenmiş sorgular, bu ilk adımda oluşan çeviri maliyetini azaltır. Özellikle sıkça çağrılan ve aynı parametrelerle kullanılan sorgular için performans artışı sağlayabilir.

Kod:
// Compiled query kullanımı (EF Core 3.0+ için Func<DbContext, int, IEnumerable<T>>)
public static Func<MyDbContext, int, IQueryable<User>> GetUsersByAge = 
    EF.CompileQuery((MyDbContext context, int age) => 
        context.Users.Where(u => u.Age > age));

// Kullanım şekli:
var usersOver30 = GetUsersByAge(_dbContext, 30).ToList();

4. Yükleme Stratejileri: Eager, Explicit ve Lazy Loading

Varlıklar arasındaki ilişkileri (bire-çok, çok-çok vb.) yönetmek EF Core'un temel özelliklerinden biridir. İlişkili verileri ne zaman ve nasıl yükleyeceğinizi seçmek, performans üzerinde doğrudan etkilidir.

  • Eager Loading (Hevesli Yükleme):
    Kod:
    Include()
    ve
    Kod:
    ThenInclude()
    kullanarak ilişkili verilerin ana sorgu ile birlikte yüklenmesini sağlar. En sık kullanılan ve genellikle en performanslı yöntemdir, çünkü N+1 sorgu sorununu önler.
  • Explicit Loading (Açık Yükleme): Varlık ana sorgu ile yüklendikten sonra, ilişkili verilerin daha sonra manuel olarak yüklenmesidir.
    Kod:
    _dbContext.Entry(user).Collection(u => u.Orders).LoadAsync()
    veya
    Kod:
    _dbContext.Entry(order).Reference(o => o.Customer).LoadAsync()
    gibi metotlar kullanılır. Sadece ihtiyaç duyulduğunda yükleme yapmak için idealdir.
  • Lazy Loading (Tembel Yükleme): İlişkili verilerin ilk kez erişildiğinde otomatik olarak yüklenmesini sağlar. Bu, geliştirme kolaylığı sunsa da, dikkatli kullanılmadığında N+1 sorgu sorununa yol açarak performans sorunları yaratabilir.
    Kod:
    Microsoft.EntityFrameworkCore.Proxies
    paketi ile etkinleştirilir ve ilişkili özelliklerin virtual olması gerekir.

Gelişmiş Veri Modelleme ve Eşleme: Esnek ve Güçlü Modeller Oluşturma

Veritabanı şemanız karmaşıklaştıkça, EF Core'un modelleme yeteneklerini daha derine inerek kullanmanız gerekebilir.

1. Sahip Olunan Varlıklar (Owned Entities)

Sahip olunan varlıklar, başka bir varlığa ait olan ve genellikle kendi kimlikleri olmayan varlıkları modellemek için kullanılır. Örneğin, bir
Kod:
Kullanıcı
varlığının
Kod:
Adres
bilgisi bir owned entity olarak modellenebilir. Bu, veritabanında genellikle aynı tabloya sütunlar ekleyerek veya ayrı bir tabloya eşlenerek (TPT gibi) gerçekleştirilir. Bu özellik, agregalar (DDD'deki) veya karmaşık değer nesnelerini modellemek için oldukça kullanışlıdır.

Kod:
// OnModelCreating içinde bir owned entity tanımlama
modelBuilder.Entity<User>().OwnsOne(u => u.Address);

// Kullanım:
var user = new User { 
    Name = "Can", 
    Address = new Address { Street = "Ana Cad.", City = "İstanbul" } 
};
_dbContext.Users.Add(user);
await _dbContext.SaveChangesAsync();

2. Gölge Özellikler (Shadow Properties)

Gölge özellikler, .NET sınıfınızda tanımlı olmayan ancak EF Core modeli içinde ve dolayısıyla veritabanı şemasında var olan özelliklerdir. Genellikle denetim (audit) bilgileri (CreatedDate, UpdatedBy) veya TenantId gibi uygulama katmanında otomatik olarak yönetilen ancak doğrudan domain modelinde yer alması istenmeyen veriler için kullanılır.

Kod:
// OnModelCreating içinde bir gölge özellik tanımlama
modelBuilder.Entity<Blog>().Property<DateTime>("LastUpdated");

// Gölge özelliğe erişim ve değer atama
var blog = new Blog { Title = "EF Core" };
_dbContext.Entry(blog).Property("LastUpdated").CurrentValue = DateTime.Now;
_dbContext.Blogs.Add(blog);
await _dbContext.SaveChangesAsync();

3. Değer Dönüştürücüler (Value Converters)

Değer dönüştürücüler, CLR tipi ile veritabanı tipi arasındaki dönüştürmeyi özelleştirmenizi sağlar. Örneğin, bir C#
Kod:
enum
değerini veritabanında string olarak saklamak veya özel bir .NET sınıfını tek bir veritabanı sütununa eşlemek için kullanılabilir. Bu, veri depolama şekli üzerinde daha fazla kontrol sağlar ve modelinizi veritabanı detaylarından soyutlar.

Kod:
public enum OrderStatus { Pending, Shipped, Delivered }

// OnModelCreating içinde bir değer dönüştürücü tanımlama
modelBuilder.Entity<Order>()
    .Property(o => o.Status)
    .HasConversion(
        v => v.ToString(),          // Enum'dan string'e dönüştürme
        v => (OrderStatus)Enum.Parse(typeof(OrderStatus), v)); // String'den enum'a dönüştürme

4. Miras Stratejileri: TPH, TPT ve TPC

EF Core, nesne yönelimli miras hiyerarşilerini veritabanına eşlemek için üç ana strateji sunar:

  • Table-Per-Hierarchy (TPH): Tüm hiyerarşiyi tek bir veritabanı tablosunda depolar. Bir discriminator sütunu, her satırın hangi türe ait olduğunu belirtir. Basit hiyerarşiler ve iyi performans için idealdir.
  • Table-Per-Type (TPT): Her sınıfı (temel sınıf ve türetilmiş sınıflar) ayrı bir veritabanı tablosuna eşler. İlişkili tablolar JOIN ile birleştirilir. Modelinizle veritabanı şemanız arasında daha yakın bir eşleşme sağlar ancak JOIN maliyetleri getirebilir.
  • Table-Per-Concrete-Type (TPC): Her somut sınıfı ayrı bir veritabanı tablosuna eşler. Temel sınıfın kendisi için bir tablo yoktur. Türetilmiş sınıflar kendi özelliklerinin yanı sıra temel sınıfın özelliklerini de kendi tablolarında içerirler. Daha az JOIN gerektirir ama veri tekrarına yol açabilir.

"Doğru miras stratejisini seçmek, hem veritabanı performansı hem de modelinizin esnekliği açısından kritik bir karardır."

Eşzamanlılık ve İşlemler: Veri Bütünlüğünü Sağlama

Çok kullanıcılı ortamlarda veritabanı bütünlüğünü korumak hayati öneme sahiptir. EF Core, bu konuda iki temel mekanizma sunar.

1. İyimser Eşzamanlılık (Optimistic Concurrency)

Birden fazla kullanıcının aynı anda aynı veriyi değiştirmeye çalıştığı senaryolarda veri kaybını önlemek için kullanılır. İyimser eşzamanlılık, veritabanı kilitleri yerine, bir verinin okunduğu andaki durumu ile yazılmaya çalışılan andaki durumu karşılaştırarak çalışır. Genellikle bir
Kod:
RowVersion
(timestamp veya byte dizisi) sütunu veya
Kod:
ConcurrencyCheck
özniteliği ile işaretlenmiş bir sütun kullanılarak uygulanır.

Kod:
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    [ConcurrencyCheck]
    public int Stock { get; set; }
}

// Eşzamanlılık çakışmasını yakalama
try
{
    await _dbContext.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException ex)
{
    foreach (var entry in ex.Entries)
    {
        // Çakışan verileri çözün (örneğin, veritabanındaki son değeri yükle)
        var databaseValues = await entry.GetDatabaseValuesAsync();
        // Kullanıcıya bildirimde bulun veya birleşme stratejisi uygula
    }
}

2. İşlem Yönetimi (Transaction Management)

Birden fazla veritabanı işlemi, tek bir atomik birim olarak yürütülmek istendiğinde işlemler kullanılır. Eğer işlemlerden biri başarısız olursa, tüm işlemler geri alınır (rollback) ve veritabanı önceki tutarlı durumuna döner. EF Core, hem örtülü (
Kod:
SaveChanges()
varsayılan olarak bir işlem içinde çalışır) hem de açık işlem yönetimi sunar.

Kod:
using var transaction = await _dbContext.Database.BeginTransactionAsync();
try
{
    // Birinci işlem
    _dbContext.Orders.Add(new Order { Amount = 100 });
    await _dbContext.SaveChangesAsync();

    // İkinci işlem
    _dbContext.Payments.Add(new Payment { Amount = 100 });
    await _dbContext.SaveChangesAsync();

    await transaction.CommitAsync();
}
catch (Exception)
{
    await transaction.RollbackAsync();
    // Hata yönetimi
}

EF Core'u Genişletme: Özel Davranışlar Uygulama

EF Core, uygulamanızın özel ihtiyaçlarına göre genişletilebilecek güçlü bir mimariye sahiptir.

1. Interceptors (Yakınlaştırıcılar)

Interceptors, EF Core'un çeşitli olaylarına (sorgu yürütme,
Kod:
SaveChanges()
, bağlantı açma vb.) müdahale etmenizi sağlar. Bu, örneğin, otomatik denetim günlüğü (audit logging) eklemek, soft-delete uygulamak veya sorguları dinamik olarak değiştirmek için çok güçlü bir araçtır. EF Core Interceptors hakkında daha fazla bilgi için resmi dokümantasyonu inceleyebilirsiniz.

Kod:
public class AuditInterceptor : SaveChangesInterceptor
{
    public override InterceptionResult SavingChanges(DbContextEventData eventData, InterceptionResult result)
    {
        foreach (var entry in eventData.Context.ChangeTracker.Entries())
        {
            if (entry.State == EntityState.Added && entry.Entity is IAuditable auditableEntity)
            {
                auditableEntity.CreatedDate = DateTime.UtcNow;
            }
        }
        return result;
    }
}

// DbContext'e interceptor ekleme
optionsBuilder.AddInterceptors(new AuditInterceptor());

2. Global Sorgu Filtreleri (Global Query Filters)

Global sorgu filtreleri, belirli bir varlık tipi için otomatik olarak tüm sorgulara uygulanan koşullardır. Bu, genellikle soft delete (
Kod:
IsDeleted = true
olan kayıtları gizleme) veya çoklu kiracılı (multi-tenant) uygulamalarda
Kod:
TenantId
filtrelemesi gibi senaryolar için kullanılır. Her sorguda bu filtreyi manuel olarak ekleme ihtiyacını ortadan kaldırır.

Kod:
// OnModelCreating içinde global sorgu filtresi tanımlama
modelBuilder.Entity<Blog>().HasQueryFilter(b => !b.IsDeleted);

// Artık tüm blog sorguları otomatik olarak IsDeleted == false olanları getirecektir
var activeBlogs = await _dbContext.Blogs.ToListAsync();

Ham SQL Sorguları ve Saklı Prosedürler: EF Core ile Doğrudan Etkileşim

Bazı durumlarda, EF Core'un LINQ sorgularıyla ifade edilemeyen veya daha iyi performans gösteren karmaşık SQL sorguları veya saklı prosedürler yazmak gerekebilir. EF Core, bu senaryolar için doğrudan veritabanıyla etkileşim kurmanıza olanak tanır.

1. Ham SQL Sorguları (FromSqlRaw / FromSqlInterpolated)

Kod:
FromSqlRaw
ve
Kod:
FromSqlInterpolated
metotları, doğrudan SQL sorgularını çalıştırarak DbSet'e eşlenmiş varlıkları döndürmek için kullanılır.
Kod:
FromSqlInterpolated
, parametreleri otomatik olarak güvenli bir şekilde ele alarak SQL enjeksiyonu riskini azaltır.

Kod:
// Ham SQL sorgusu ile veri çekme (parametreler güvende)
var users = await _dbContext.Users
    .FromSqlInterpolated($"SELECT * FROM Users WHERE Age > {minAge}")
    .ToListAsync();

2. Ham SQL Komutları ve Saklı Prosedürler (ExecuteSqlRaw / ExecuteSqlInterpolated)

Veritabanında INSERT, UPDATE, DELETE gibi işlemler yapmak veya saklı prosedürleri çağırmak için
Kod:
ExecuteSqlRaw
ve
Kod:
ExecuteSqlInterpolated
metotları kullanılır. Bu metotlar, etkiilenen satır sayısını döndürür ve bir DbSet'e eşleme yapmazlar.

Kod:
// Veritabanında güncelleme işlemi
var affectedRows = await _dbContext.Database
    .ExecuteSqlInterpolated($"UPDATE Products SET Stock = Stock - {quantity} WHERE Id = {productId}");

// Saklı prosedür çağırma
var result = await _dbContext.Database
    .ExecuteSqlRawAsync("EXECUTE sp_UpdateOrderStatus @p0, @p1", parameters: new[] { orderId, newStatus });

En İyi Uygulamalar ve İpuçları

EF Core ile çalışırken performansı ve sürdürülebilirliği artırmak için bazı genel en iyi uygulamalar şunlardır:

  • Asenkron Metotlar Kullanın: Veritabanı işlemleri G/Ç yoğun operasyonlar olduğu için,
    Kod:
    async
    /
    Kod:
    await
    kullanarak UI veya API iş parçacıklarının bloke olmasını engelleyin.
  • DbContext Yaşam Döngüsünü Yönetin: Genellikle kısa ömürlü (scoped) DbContext örnekleri kullanın ve her iş birimi için yeni bir örnek oluşturun. Uzun ömürlü DbContext'ler bellek ve değişiklik takibi sorunlarına yol açabilir.
  • Doğru İndekslemeyi Yapın: Sorgularınızda sıkça kullanılan sütunları veritabanında doğru bir şekilde indeksleyin. EF Core migrasyonları aracılığıyla indeksleri yönetebilirsiniz.
  • Loglama ve Profilleme: EF Core'un dahili loglama mekanizmalarını veya harici araçları (örneğin, MiniProfiler) kullanarak sorguları izleyin ve performans darboğazlarını tespit edin. EF Core Loglama hakkında bilgi.
  • Veritabanı Şemasını Optimize Edin: Modeliniz ve veritabanı şemanız arasındaki uyumu iyi kurun. Normalizasyon seviyesi, veri tipleri gibi veritabanı tasarım prensiplerine dikkat edin.

Sonuç

Entity Framework Core, modern .NET uygulamaları için vazgeçilmez bir araçtır. Temel özelliklerinin yanı sıra, bu makalede ele aldığımız ileri seviye teknikler sayesinde, EF Core'u en verimli şekilde kullanarak uygulamalarınızın performansını, ölçeklenebilirliğini ve sürdürülebilirliğini önemli ölçüde artırabilirsiniz. Performans optimizasyonlarından gelişmiş veri modellemeye, eşzamanlılık yönetiminden EF Core'u genişletmeye kadar birçok alanda sunulan bu yetenekler, karmaşık iş gereksinimlerini karşılamanıza ve daha sağlam yazılımlar geliştirmenize olanak tanır. EF Core dünyasındaki yenilikleri takip etmek ve bu ileri seviye özelliklere hakim olmak, bir geliştirici olarak sizi rakiplerinizden bir adım öne taşıyacaktır. Her projede olduğu gibi, ihtiyaçlara göre doğru araçları ve stratejileri seçmek anahtardır.
 
shape1
shape2
shape3
shape4
shape5
shape6
Üst

Bu web sitenin performansı Hazal Host tarafından sağlanmaktadır.

YazilimForum.com.tr internet sitesi, 5651 sayılı Kanun’un 2. maddesinin 1. fıkrasının (m) bendi ve aynı Kanun’un 5. maddesi kapsamında Yer Sağlayıcı konumundadır. Sitede yer alan içerikler ön onay olmaksızın tamamen kullanıcılar tarafından oluşturulmaktadır.

YazilimForum.com.tr, kullanıcılar tarafından paylaşılan içeriklerin doğruluğunu, güncelliğini veya hukuka uygunluğunu garanti etmez ve içeriklerin kontrolü veya araştırılması ile yükümlü değildir. Kullanıcılar, paylaştıkları içeriklerden tamamen kendileri sorumludur.

Hukuka aykırı içerikleri fark ettiğinizde lütfen bize bildirin: lydexcoding@gmail.com

Sitemiz, kullanıcıların paylaştığı içerik ve bilgileri 6698 sayılı KVKK kapsamında işlemektedir. Kullanıcılar, kişisel verileriyle ilgili haklarını KVKK Politikası sayfasından inceleyebilir.

Sitede yer alan reklamlar veya üçüncü taraf bağlantılar için YazilimForum.com.tr herhangi bir sorumluluk kabul etmez.

Sitemizi kullanarak Forum Kuralları’nı kabul etmiş sayılırsınız.

DMCA.com Protection Status Copyrighted.com Registered & Protected