SQLite Nedir? Neden SQLite? C# SQLite Bağlantısı

SQLite Nedir?

[!NOTE] Hızlı Karşılaştırma: SQLite vs MySQL Neden SQLite seçmelisiniz? İşte kısa bir özet:

ÖzellikSQLiteMySQL / PostgreSQL
KurulumGerektirmez (Tek Dosya)Sunucu Kurulumu Gerekir
DepolamaTek bir .db dosyasıKarmaşık Dosya Sistemi
Kullanıcı YönetimiYok (Dosya İzinleri)Gelişmiş Kullanıcı Yönetimi
En İyi KullanımMobil, IoT, Küçük Web SiteleriBüyük Web Siteleri, Kurumsal

SQLite, tamamen açık kaynak kodlu, hafif bir ilişkisel veritabanı yönetim sistemidir (RDBMS). En önemli özelliği, sunucu gerektirmemesi ve tamamen dosya tabanlı çalışmasıdır. Tüm veritabanı tek bir dosyada saklanır, bu da kurulum ve dağıtımı son derece kolaylaştırır.

SQLite’ın Temel Özellikleri

  • Sıfır Konfigürasyon: Kurulum gerektirmez, sadece bir DLL veya native library yeterlidir
  • Düşük Kaynak Kullanımı: Minimal bellek ve CPU kullanımı
  • ACID Uyumlu: Transaction desteği ile veri bütünlüğü garantisi
  • Platform Bağımsız: Windows, Linux, macOS, iOS, Android ve daha fazlasında çalışır
  • Yüksek Performans: Küçük ve orta ölçekli uygulamalar için optimize edilmiştir
  • SQL Standartlarına Uyum: SQL-92 standardının büyük bir kısmını destekler

SQLite’ın Kullanım Alanları

  • Mobil Uygulamalar: iOS ve Android uygulamalarında yerel veri depolama
  • Masaüstü Uygulamaları: Offline çalışan desktop uygulamaları
  • Gömülü Sistemler: IoT cihazları ve embedded sistemler
  • Prototipleme: Hızlı geliştirme ve test aşamaları
  • Küçük Web Uygulamaları: Düşük trafikli web siteleri
  • Cache Mekanizmaları: Geçici veri depolama çözümleri

Neden SQLite Tercih Edilmeli?

Gerçek Hayat Senaryosu

Bir bina ve ofis yönetim yazılımı geliştirme projesinde, müşteri mevcut sistemin çok yavaş olduğundan şikayetçiydi. Çözüm için birkaç seçenek vardı:

  1. Merkezi Sunucu: Intranet ağı gerektiriyordu, ekstra maliyet
  2. Local Sunucu: Eski makinelere yük olacaktı
  3. SQLite: Dosya tabanlı, düşük kaynak kullanımı, hızlı

SQLite seçimi sayesinde:

  • Sunucu kurulum maliyeti ortadan kalktı
  • Eski donanımlarda bile sorunsuz çalıştı
  • Performans sorunları çözüldü
  • Dağıtım ve bakım kolaylaştı

SQLite’ın Avantajları

1. Basitlik ve Hız

  • Sunucu yönetimi yok
  • Network gecikmesi yok
  • Dosya sistemi üzerinden direkt erişim

2. Düşük Maliyet

  • Sunucu lisansı gerekmez
  • Hosting maliyeti yok
  • Minimum sistem gereksinimleri

3. Güvenilirlik

  • Yıllardır test edilmiş, stabil
  • Büyük şirketler tarafından kullanılıyor (Google, Apple, Microsoft)
  • Veri kaybı riski minimal

4. Esneklik

  • Veritabanı dosyasını kolayca yedekleyebilirsiniz
  • Farklı platformlar arasında taşınabilir
  • Versiyon kontrol sistemlerine eklenebilir

SQLite’ın Sınırlamaları

SQLite her durum için uygun değildir:

  • Eşzamanlı Yazma İşlemleri: Çok sayıda eşzamanlı yazma işlemi için uygun değil
  • Büyük Veri Setleri: Terabayt seviyesinde veriler için önerilmez
  • Network Erişimi: Ağ üzerinden erişim gerektiren durumlarda uygun değil
  • Çok Kullanıcılı Sistemler: Merkezi bir veritabanı sunucusu gerektiren durumlar

SQLite Kurulumu ve Kullanımı

1. Veritabanı Editörü Seçimi

SQLite veritabanınızı yönetmek için bir editöre ihtiyacınız var:

Önerilen Araçlar:

  • DB Browser for SQLite: Ücretsiz, açık kaynak, kullanıcı dostu
  • SQLiteStudio: Platform bağımsız, güçlü özellikler
  • DBeaver: Çoklu veritabanı desteği
  • VS Code Eklentileri: SQLite Viewer, SQLite gibi eklentiler

2. NuGet Paket Kurulumu

.NET projelerinde SQLite kullanmak için birkaç seçenek var:

Seçenek 1: System.Data.SQLite (ADO.NET)

PM> Install-Package System.Data.SQLite

Seçenek 2: Microsoft.EntityFrameworkCore.Sqlite (Entity Framework Core)

PM> Install-Package Microsoft.EntityFrameworkCore.Sqlite
PM> Install-Package Microsoft.EntityFrameworkCore.Design

Seçenek 3: Microsoft.Data.Sqlite (.NET Core/5+)

PM> Install-Package Microsoft.Data.Sqlite

3. Veritabanı Dosyası Oluşturma

SQLite veritabanı dosyaları genellikle .db, .sqlite, veya .sqlite3 uzantısı kullanır. Modern uygulamalarda .db veya .sqlite3 tercih edilir.

C# ile SQLite Kullanım Örnekleri

Örnek 1: ADO.NET ile Temel İşlemler

using System.Data.SQLite;
using System.IO;

public class SQLiteHelper
{
    private readonly string _connectionString;
    
    public SQLiteHelper(string dbPath)
    {
        _connectionString = $"Data Source={dbPath};Version=3;";
        
        // Veritabanı dosyası yoksa oluştur
        if (!File.Exists(dbPath))
        {
            SQLiteConnection.CreateFile(dbPath);
        }
    }
    
    // Veri Ekleme (Parametreli Sorgu - SQL Injection'a karşı güvenli)
    public void InsertData(string name, string email)
    {
        using var connection = new SQLiteConnection(_connectionString);
        connection.Open();
        
        const string query = @"
            INSERT INTO Users (Name, Email, CreatedDate) 
            VALUES (@name, @email, @createdDate)";
        
        using var command = new SQLiteCommand(query, connection);
        command.Parameters.AddWithValue("@name", name);
        command.Parameters.AddWithValue("@email", email);
        command.Parameters.AddWithValue("@createdDate", DateTime.Now);
        
        command.ExecuteNonQuery();
    }
    
    // Veri Okuma
    public List<User> GetAllUsers()
    {
        var users = new List<User>();
        
        using var connection = new SQLiteConnection(_connectionString);
        connection.Open();
        
        const string query = "SELECT Id, Name, Email, CreatedDate FROM Users";
        
        using var command = new SQLiteCommand(query, connection);
        using var reader = command.ExecuteReader();
        
        while (reader.Read())
        {
            users.Add(new User
            {
                Id = reader.GetInt32(0),
                Name = reader.GetString(1),
                Email = reader.GetString(2),
                CreatedDate = reader.GetDateTime(3)
            });
        }
        
        return users;
    }
    
    // Veri Güncelleme
    public void UpdateUser(int id, string name, string email)
    {
        using var connection = new SQLiteConnection(_connectionString);
        connection.Open();
        
        const string query = @"
            UPDATE Users 
            SET Name = @name, Email = @email 
            WHERE Id = @id";
        
        using var command = new SQLiteCommand(query, connection);
        command.Parameters.AddWithValue("@id", id);
        command.Parameters.AddWithValue("@name", name);
        command.Parameters.AddWithValue("@email", email);
        
        command.ExecuteNonQuery();
    }
    
    // Veri Silme
    public void DeleteUser(int id)
    {
        using var connection = new SQLiteConnection(_connectionString);
        connection.Open();
        
        const string query = "DELETE FROM Users WHERE Id = @id";
        
        using var command = new SQLiteCommand(query, connection);
        command.Parameters.AddWithValue("@id", id);
        
        command.ExecuteNonQuery();
    }
    
    // Transaction Örneği
    public void InsertMultipleUsers(List<(string name, string email)> users)
    {
        using var connection = new SQLiteConnection(_connectionString);
        connection.Open();
        
        using var transaction = connection.BeginTransaction();
        
        try
        {
            const string query = @"
                INSERT INTO Users (Name, Email, CreatedDate) 
                VALUES (@name, @email, @createdDate)";
            
            foreach (var (name, email) in users)
            {
                using var command = new SQLiteCommand(query, connection, transaction);
                command.Parameters.AddWithValue("@name", name);
                command.Parameters.AddWithValue("@email", email);
                command.Parameters.AddWithValue("@createdDate", DateTime.Now);
                command.ExecuteNonQuery();
            }
            
            transaction.Commit();
        }
        catch
        {
            transaction.Rollback();
            throw;
        }
    }
    
    // Tablo Oluşturma
    public void CreateUsersTable()
    {
        using var connection = new SQLiteConnection(_connectionString);
        connection.Open();
        
        const string query = @"
            CREATE TABLE IF NOT EXISTS Users (
                Id INTEGER PRIMARY KEY AUTOINCREMENT,
                Name TEXT NOT NULL,
                Email TEXT NOT NULL UNIQUE,
                CreatedDate DATETIME NOT NULL
            )";
        
        using var command = new SQLiteCommand(query, connection);
        command.ExecuteNonQuery();
    }
}

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public DateTime CreatedDate { get; set; }
}

Örnek 2: Async/Await ile Modern C# Kullanımı

using System.Data.SQLite;
using System.Threading.Tasks;

public class AsyncSQLiteHelper
{
    private readonly string _connectionString;
    
    public AsyncSQLiteHelper(string dbPath)
    {
        _connectionString = $"Data Source={dbPath};Version=3;";
    }
    
    // Async Veri Ekleme
    public async Task<int> InsertUserAsync(string name, string email)
    {
        await using var connection = new SQLiteConnection(_connectionString);
        await connection.OpenAsync();
        
        const string query = @"
            INSERT INTO Users (Name, Email, CreatedDate) 
            VALUES (@name, @email, @createdDate);
            SELECT last_insert_rowid();";
        
        await using var command = new SQLiteCommand(query, connection);
        command.Parameters.AddWithValue("@name", name);
        command.Parameters.AddWithValue("@email", email);
        command.Parameters.AddWithValue("@createdDate", DateTime.Now);
        
        var result = await command.ExecuteScalarAsync();
        return Convert.ToInt32(result);
    }
    
    // Async Veri Okuma
    public async Task<List<User>> GetUsersAsync()
    {
        var users = new List<User>();
        
        await using var connection = new SQLiteConnection(_connectionString);
        await connection.OpenAsync();
        
        const string query = "SELECT Id, Name, Email, CreatedDate FROM Users";
        
        await using var command = new SQLiteCommand(query, connection);
        await using var reader = await command.ExecuteReaderAsync();
        
        while (await reader.ReadAsync())
        {
            users.Add(new User
            {
                Id = reader.GetInt32(0),
                Name = reader.GetString(1),
                Email = reader.GetString(2),
                CreatedDate = reader.GetDateTime(3)
            });
        }
        
        return users;
    }
}

Örnek 3: Entity Framework Core ile Kullanım

using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

// DbContext Tanımı
public class AppDbContext : DbContext
{
    public DbSet<User> Users { get; set; }
    
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite("Data Source=app.db");
    }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>(entity =>
        {
            entity.HasKey(e => e.Id);
            entity.Property(e => e.Email).IsRequired().HasMaxLength(255);
            entity.HasIndex(e => e.Email).IsUnique();
        });
    }
}

// Entity Sınıfı
[Table("Users")]
public class User
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    
    [Required]
    [MaxLength(255)]
    public string Name { get; set; }
    
    [Required]
    [MaxLength(255)]
    public string Email { get; set; }
    
    public DateTime CreatedDate { get; set; }
}

// Kullanım Örnekleri
public class UserService
{
    private readonly AppDbContext _context;
    
    public UserService(AppDbContext context)
    {
        _context = context;
    }
    
    // Veri Ekleme
    public async Task<User> CreateUserAsync(string name, string email)
    {
        var user = new User
        {
            Name = name,
            Email = email,
            CreatedDate = DateTime.Now
        };
        
        _context.Users.Add(user);
        await _context.SaveChangesAsync();
        return user;
    }
    
    // Veri Okuma
    public async Task<List<User>> GetAllUsersAsync()
    {
        return await _context.Users
            .OrderBy(u => u.CreatedDate)
            .ToListAsync();
    }
    
    // LINQ ile Sorgulama
    public async Task<User> GetUserByEmailAsync(string email)
    {
        return await _context.Users
            .FirstOrDefaultAsync(u => u.Email == email);
    }
    
    // Veri Güncelleme
    public async Task UpdateUserAsync(int id, string name, string email)
    {
        var user = await _context.Users.FindAsync(id);
        if (user != null)
        {
            user.Name = name;
            user.Email = email;
            await _context.SaveChangesAsync();
        }
    }
    
    // Veri Silme
    public async Task DeleteUserAsync(int id)
    {
        var user = await _context.Users.FindAsync(id);
        if (user != null)
        {
            _context.Users.Remove(user);
            await _context.SaveChangesAsync();
        }
    }
}

Örnek 4: Dependency Injection ile Kullanım (.NET Core/5+)

// Startup.cs veya Program.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<AppDbContext>(options =>
        options.UseSqlite("Data Source=app.db"));
    
    services.AddScoped<UserService>();
}

// Controller veya Service
public class UserController : ControllerBase
{
    private readonly UserService _userService;
    
    public UserController(UserService userService)
    {
        _userService = userService;
    }
    
    [HttpPost]
    public async Task<IActionResult> CreateUser([FromBody] CreateUserDto dto)
    {
        var user = await _userService.CreateUserAsync(dto.Name, dto.Email);
        return Ok(user);
    }
}

Best Practices ve Öneriler

1. Connection String Yönetimi

// appsettings.json
{
  "ConnectionStrings": {
    "DefaultConnection": "Data Source=app.db;Version=3;Cache=Shared;"
  }
}

// Connection String Parametreleri
// Cache=Shared: Bellek cache'i paylaşır (performans artışı)
// Foreign Keys=True: Foreign key kısıtlamalarını aktif eder
// Journal Mode=WAL: Write-Ahead Logging modu (daha iyi performans)

2. Connection Pooling

SQLite connection pooling’i otomatik yönetir, ancak using statement kullanarak bağlantıları düzgün kapatmak önemlidir.

3. Performans İpuçları

  • Index Kullanımı: Sık sorgulanan kolonlara index ekleyin
  • Batch İşlemler: Çoklu insert için transaction kullanın
  • WAL Modu: Write-Ahead Logging modunu aktif edin
  • Prepared Statements: Parametreli sorgular kullanın (SQL Injection koruması + performans)

4. Güvenlik

  • Parametreli Sorgular: Her zaman parametreli sorgular kullanın
  • Input Validation: Kullanıcı girdilerini doğrulayın
  • Backup: Düzenli olarak veritabanı dosyasını yedekleyin

5. Migration ve Schema Yönetimi

Entity Framework Core ile migration kullanın:

PM> Add-Migration InitialCreate
PM> Update-Database

Sonuç

SQLite, özellikle küçük ve orta ölçekli uygulamalar için mükemmel bir seçenektir. Sunucu gerektirmemesi, düşük kaynak kullanımı ve kolay dağıtım özellikleri sayesinde birçok senaryoda ideal çözümdür. Modern .NET uygulamalarında Entity Framework Core veya ADO.NET ile rahatlıkla kullanılabilir.

Ne Zaman SQLite Kullanmalı?

  • Offline çalışan uygulamalar
  • Prototip ve test projeleri
  • Küçük ve orta ölçekli veri setleri
  • Sunucu kurulumu yapılamayan ortamlar
  • Mobil ve embedded uygulamalar

Ne Zaman Kullanmamalı?

  • Çok sayıda eşzamanlı yazma işlemi gerektiren durumlar
  • Network üzerinden erişim gerektiren sistemler
  • Terabayt seviyesinde veri setleri
  • Merkezi veritabanı sunucusu gerektiren kurumsal uygulamalar
Please enable JavaScript to view the comments powered by Disqus.