Teknoloji, Bilim ve Akıl
C# WinForms Uygulamasında SQLite Kullanımı Adım Adım
Masaüstü Programlama

C# WinForms Uygulamasında SQLite Kullanımı Adım Adım

8 dk okuma 14 okunma 0 yorum
İçindekiler
  1. Kısa Özet
  2. SQLite nedir, masaüstü uygulamada neden tercih edilir?
  3. Hangi SQLite paketi seçilmeli?
  4. Adım 1: Proje nasıl oluşturulur ve paket nasıl eklenir?
  5. Adım 2: Veritabanı dosyası nereye konmalı?
  6. Adım 3: Veritabanı sınıfı nasıl yazılır?
  7. Adım 4: Kayıt nasıl eklenir?
  8. Adım 5: Kayıtlar DataGridView ile nasıl listelenir?
  9. Türkçe aramada neden ayrı bir sütun kullandık?
  10. Adım 6: Kayıt nasıl güncellenir ve silinir?
  11. Adım 7: Toplu kayıt nasıl hızlı eklenir?
  12. Adım 8: Form donmadan uzun sorgu nasıl çalıştırılır?
  13. Veritabanı yedeği nasıl alınır?
  14. Tablo yapısı sonradan nasıl güncellenir?
  15. Sahadan notlar: Fabrika uygulamalarında SQLite
  16. Sık karşılaşılan hatalar ve çözümleri
  17. Sıkça Sorulan Sorular
  18. SQLite ile kaç kayıt saklanabilir?
  19. SQLite veritabanını ağdaki ortak klasörde paylaşabilir miyim?
  20. Microsoft.Data.Sqlite ile System.Data.SQLite arasındaki fark nedir?
  21. SQLite veritabanına şifre koyabilir miyim?
  22. Veritabanı dosyasını hangi programla açıp inceleyebilirim?
  23. WinForms uygulaması SQLite ile tek exe olarak dağıtılabilir mi?

C# WinForms uygulamasında SQLite kullanmak için projeye NuGet üzerinden Microsoft.Data.Sqlite paketini eklemeniz, veritabanı dosyasının yolunu belirlemeniz ve SqliteConnection ile bağlantı açıp SQL komutlarını parametreli olarak çalıştırmanız yeterlidir. Sunucu kurulumu, servis ayarı veya kullanıcı tanımlama gerekmez. Veritabanı tek bir .db dosyasıdır ve uygulamanızla birlikte taşınır.

Bu rehberde sıfırdan küçük bir Müşteri Defteri uygulaması kuruyoruz. Kayıt ekleme, listeleme, arama, güncelleme, silme, toplu ekleme ve yedekleme adımlarının hepsi örnek kodlarla anlatılıyor. Sonda fabrikadaki masaüstü uygulamalarımızda karşılaştığımız gerçek sorunlara da yer verdik.

Kısa Özet

  • Paket: .NET 8 ve üzeri için Microsoft.Data.Sqlite. Çok eski .NET Framework projelerinde System.Data.SQLite.
  • Dosya yeri: Veritabanını Program Files içine değil, kullanıcının AppData klasörüne koyun.
  • Güvenlik: Sorgulara değer eklerken her zaman parametre kullanın, metin birleştirmeyin.
  • Hız: Toplu eklemeleri tek bir transaction içinde yapın.
  • Arayüz: Uzun sorguları Task.Run ile arka planda çalıştırın, form donmasın.
  • Türkçe dikkat: SQLite LIKE araması Türkçe büyük küçük harf ayrımını doğru yapmaz, çözümü aşağıda.

SQLite nedir, masaüstü uygulamada neden tercih edilir?

SQLite, ayrı bir sunucu gerektirmeyen, tek dosyada çalışan ilişkisel bir veritabanıdır. Uygulama veritabanı motorunu kendi içinde taşır ve dosyaya doğrudan okuyup yazar. Bu yüzden tek kullanıcılı masaüstü uygulamalar, saha cihazları ve çevrimdışı çalışması gereken programlar için en pratik seçenektir.

Özellik SQLite SQL Server Express MS Access
Kurulum Yok, tek dosya Sunucu kurulumu gerekir Access motoru gerekir
Taşınabilirlik Dosyayı kopyalamak yeterli Yedekle ve geri yükle Dosyayı kopyalamak yeterli
Çok kullanıcılı ağ erişimi Uygun değil Uygun Sınırlı ve riskli
32 ve 64 bit sorunu Paket yönetir Yok Sık görülür
Uygun kullanım Tek bilgisayar, yerel veri, tampon kayıt Ağdaki çok kullanıcılı sistemler Eski projelerin bakımı

Kısacası veri tek bilgisayarda kalacaksa SQLite, birden fazla bilgisayar aynı veriye aynı anda yazacaksa MySQL veya SQL Server tercih edilmelidir.

Hangi SQLite paketi seçilmeli?

C# tarafında iki yaygın paket vardır. İkisi de aynı SQLite motorunu kullanır, farkları API ve desteklenen platformlardadır.

Özellik Microsoft.Data.Sqlite System.Data.SQLite
Geliştiren Microsoft (.NET ekibi) SQLite geliştiricileri
Uygun proje .NET 8 ve üzeri, ayrıca .NET Framework 4.6.1 ve üzeri Eski .NET Framework projeleri dahil geniş yelpaze
DataAdapter desteği Yok, DataTable.Load kullanılır Var
Yapı Hafif, modern Daha kapsamlı, eski API alışkanlıklarına yakın

Yeni bir WinForms projesi açıyorsanız Microsoft.Data.Sqlite ile başlayın. Bu rehberdeki kodlar bu pakete göre yazıldı.

Adım 1: Proje nasıl oluşturulur ve paket nasıl eklenir?

  1. Visual Studio açın ve Windows Forms App şablonunu seçin. .NET Framework değil, .NET sürümü olanı seçin.
  2. Proje adını MusteriDefteri yapın.
  3. Çözüm Gezgini üzerinde projeye sağ tıklayıp NuGet Paketlerini Yönet seçeneğine girin.
  4. Microsoft.Data.Sqlite paketini arayın ve en güncel kararlı sürümü kurun.

Komut satırını tercih ediyorsanız proje klasöründe şu komutu çalıştırmanız yeterlidir:

dotnet add package Microsoft.Data.Sqlite

Adım 2: Veritabanı dosyası nereye konmalı?

En sık yapılan hata veritabanı dosyasını exe dosyasının yanına koymaktır. Uygulama Program Files altına kurulduğunda Windows bu klasöre yazma izni vermez ve uygulama yönetici olarak açılmadıkça kayıt yapamaz.

Doğru yer kullanıcının yerel uygulama verileri klasörüdür. Bu klasör her kullanıcı için ayrıdır ve yazma izni her zaman vardır. Taşınabilir (kurulumsuz) bir program yapıyorsanız exe yanında tutmak kabul edilebilir, ancak programın USB veya masaüstü gibi yazılabilir bir klasörden çalıştırılması gerekir.

Adım 3: Veritabanı sınıfı nasıl yazılır?

Bağlantı ve tablo oluşturma işlerini tek bir sınıfta toplamak, formların kodunu sade tutar. Projeye Db.cs adında yeni bir sınıf ekleyin:

using Microsoft.Data.Sqlite;

namespace MusteriDefteri;

public static class Db
{
    private static readonly string Klasor = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
        "MusteriDefteri");

    public static readonly string DosyaYolu = Path.Combine(Klasor, "veri.db");

    public static SqliteConnection Ac()
    {
        var baglanti = new SqliteConnection($"Data Source={DosyaYolu}");
        baglanti.Open();

        using var komut = baglanti.CreateCommand();
        komut.CommandText = "PRAGMA foreign_keys = ON; PRAGMA busy_timeout = 5000;";
        komut.ExecuteNonQuery();

        return baglanti;
    }

    public static void Hazirla()
    {
        Directory.CreateDirectory(Klasor);

        using var baglanti = Ac();
        using var komut = baglanti.CreateCommand();
        komut.CommandText = @"
            PRAGMA journal_mode = WAL;

            CREATE TABLE IF NOT EXISTS musteriler (
                id          INTEGER PRIMARY KEY AUTOINCREMENT,
                ad          TEXT NOT NULL,
                ad_arama    TEXT NOT NULL,
                telefon     TEXT,
                notlar      TEXT,
                eklenme     TEXT NOT NULL DEFAULT (datetime('now','localtime'))
            );

            CREATE INDEX IF NOT EXISTS ix_musteriler_ad_arama ON musteriler(ad_arama);";
        komut.ExecuteNonQuery();
    }
}

Buradaki ayarların görevleri şöyledir:

  • foreign_keys = ON: SQLite yabancı anahtar kurallarını varsayılan olarak uygulamaz. Her bağlantıda açılması gerekir.
  • busy_timeout = 5000: Dosya başka bir işlem tarafından kilitliyse hemen hata vermek yerine 5 saniyeye kadar bekler.
  • journal_mode = WAL: Okuma ve yazma işlemlerinin birbirini daha az bekletmesini sağlar. Bir kez ayarlanması yeterlidir, dosyada kalıcıdır.
  • ad_arama sütunu: Türkçe arama sorununu çözmek için eklendi, aşağıda açıklanıyor.

Uygulama açılırken tabloların hazır olması için Program.cs dosyasında formu açmadan önce bu metodu çağırın:

ApplicationConfiguration.Initialize();
Db.Hazirla();
Application.Run(new Form1());

Adım 4: Kayıt nasıl eklenir?

Forma txtAd, txtTelefon, txtNot adında üç TextBox, btnKaydet adında bir Button ve dgvListe adında bir DataGridView ekleyin. Kaydet butonunun kodu şöyledir:

using System.Globalization;
using Microsoft.Data.Sqlite;

private static readonly CultureInfo Tr = new("tr-TR");

private void btnKaydet_Click(object sender, EventArgs e)
{
    string ad = txtAd.Text.Trim();
    if (ad.Length == 0)
    {
        MessageBox.Show("Müşteri adı boş bırakılamaz.", "Uyarı",
            MessageBoxButtons.OK, MessageBoxIcon.Warning);
        return;
    }

    using var baglanti = Db.Ac();
    using var komut = baglanti.CreateCommand();
    komut.CommandText = @"INSERT INTO musteriler (ad, ad_arama, telefon, notlar)
                          VALUES ($ad, $adArama, $tel, $not)";
    komut.Parameters.AddWithValue("$ad", ad);
    komut.Parameters.AddWithValue("$adArama", ad.ToLower(Tr));
    komut.Parameters.AddWithValue("$tel", txtTelefon.Text.Trim());
    komut.Parameters.AddWithValue("$not", txtNot.Text.Trim());
    komut.ExecuteNonQuery();

    txtAd.Clear();
    txtTelefon.Clear();
    txtNot.Clear();
    Listele();
}

Değerler SQL metnine eklenmiyor, $ad gibi parametrelerle gönderiliyor. Böylece müşteri adında tek tırnak olsa bile sorgu bozulmaz ve SQL injection riski ortadan kalkar. Konunun web tarafını PHP ile SQL injection önleme rehberimizde anlatmıştık, mantık C# tarafında da aynıdır.

Adım 5: Kayıtlar DataGridView ile nasıl listelenir?

Microsoft.Data.Sqlite paketinde DataAdapter yoktur. Bunun yerine okuyucudan gelen veriyi DataTable.Load ile tabloya aktarıp DataGridView kaynağına veriyoruz:

using System.Data;

private void Listele(string arama = "")
{
    using var baglanti = Db.Ac();
    using var komut = baglanti.CreateCommand();
    komut.CommandText = @"SELECT id AS No, ad AS Ad, telefon AS Telefon,
                                 notlar AS Notlar, eklenme AS Eklenme
                          FROM musteriler
                          WHERE ad_arama LIKE $ara
                          ORDER BY id DESC
                          LIMIT 500";
    komut.Parameters.AddWithValue("$ara", "%" + arama.Trim().ToLower(Tr) + "%");

    using var okuyucu = komut.ExecuteReader();
    var tablo = new DataTable();
    tablo.Load(okuyucu);

    dgvListe.DataSource = tablo;
    dgvListe.Columns["No"].Visible = false;
}

private void Form1_Load(object sender, EventArgs e)
{
    dgvListe.ReadOnly = true;
    dgvListe.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
    dgvListe.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
    Listele();
}

private void txtAra_TextChanged(object sender, EventArgs e)
{
    Listele(txtAra.Text);
}

LIMIT 500 ifadesi bilinçli olarak eklendi. Kayıt sayısı on binleri bulduğunda tüm tabloyu ekrana basmak formu yavaşlatır. Kullanıcı zaten arama kutusuyla aradığını bulur.

Türkçe aramada neden ayrı bir sütun kullandık?

SQLite LIKE operatörü büyük küçük harf duyarsızlığını yalnızca İngilizce harfler için uygular. Bu yüzden Şahin adıyla kayıtlı bir müşteri şahin yazılarak bulunamaz. I ve İ harflerinde durum daha da karışıktır.

En sağlam çözüm, adı kaydederken Türkçe kurallarla küçük harfe çevirip ayrı bir sütunda tutmak ve aramayı da küçük harfe çevrilmiş metinle o sütunda yapmaktır. Yukarıdaki kodlarda ad_arama sütunu tam olarak bu işi görüyor. Bu sütuna eklediğimiz index sayesinde arama da hızlı kalıyor. Index mantığını SQL index rehberimizde ayrıntılı anlattık.

Adım 6: Kayıt nasıl güncellenir ve silinir?

Seçili satırın kimliğini DataGridView üzerinden alıp güncelleme ve silme sorgularına parametre olarak veriyoruz:

private long? SeciliId()
{
    if (dgvListe.CurrentRow == null) return null;
    return Convert.ToInt64(dgvListe.CurrentRow.Cells["No"].Value);
}

private void btnGuncelle_Click(object sender, EventArgs e)
{
    if (SeciliId() is not long id) return;
    string ad = txtAd.Text.Trim();
    if (ad.Length == 0) return;

    using var baglanti = Db.Ac();
    using var komut = baglanti.CreateCommand();
    komut.CommandText = @"UPDATE musteriler
                          SET ad = $ad, ad_arama = $adArama, telefon = $tel, notlar = $not
                          WHERE id = $id";
    komut.Parameters.AddWithValue("$ad", ad);
    komut.Parameters.AddWithValue("$adArama", ad.ToLower(Tr));
    komut.Parameters.AddWithValue("$tel", txtTelefon.Text.Trim());
    komut.Parameters.AddWithValue("$not", txtNot.Text.Trim());
    komut.Parameters.AddWithValue("$id", id);
    komut.ExecuteNonQuery();
    Listele(txtAra.Text);
}

private void btnSil_Click(object sender, EventArgs e)
{
    if (SeciliId() is not long id) return;

    var cevap = MessageBox.Show("Seçili müşteri silinsin mi? Bu işlem geri alınamaz.",
        "Silme onayı", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
    if (cevap != DialogResult.Yes) return;

    using var baglanti = Db.Ac();
    using var komut = baglanti.CreateCommand();
    komut.CommandText = "DELETE FROM musteriler WHERE id = $id";
    komut.Parameters.AddWithValue("$id", id);
    komut.ExecuteNonQuery();
    Listele(txtAra.Text);
}

Satıra tıklandığında bilgilerin kutulara dolması için DataGridView SelectionChanged olayında seçili satırın Ad, Telefon ve Notlar hücrelerini ilgili TextBox alanlarına aktarmanız yeterlidir.

Adım 7: Toplu kayıt nasıl hızlı eklenir?

Excel veya metin dosyasından yüzlerce kayıt aktarırken her INSERT işlemi ayrı ayrı diske yazılırsa işlem dakikalar sürebilir. Tüm eklemeleri tek bir transaction içine aldığınızda disk yazma işlemi bir kez yapılır ve aktarım çok daha hızlı tamamlanır.

public static void TopluEkle(IEnumerable<(string Ad, string Telefon)> liste)
{
    var tr = new CultureInfo("tr-TR");

    using var baglanti = Db.Ac();
    using var islem = baglanti.BeginTransaction();
    using var komut = baglanti.CreateCommand();
    komut.Transaction = islem;
    komut.CommandText = @"INSERT INTO musteriler (ad, ad_arama, telefon)
                          VALUES ($ad, $adArama, $tel)";

    var pAd = komut.Parameters.Add("$ad", SqliteType.Text);
    var pAdArama = komut.Parameters.Add("$adArama", SqliteType.Text);
    var pTel = komut.Parameters.Add("$tel", SqliteType.Text);

    foreach (var m in liste)
    {
        pAd.Value = m.Ad;
        pAdArama.Value = m.Ad.ToLower(tr);
        pTel.Value = m.Telefon;
        komut.ExecuteNonQuery();
    }

    islem.Commit();
}

Komut ve parametreler döngünün dışında bir kez oluşturuluyor, döngüde sadece değerler değişiyor. Bu da ayrıca hız kazandırır. Herhangi bir satırda hata çıkarsa Commit çağrılmadığı için hiçbir kayıt yazılmaz, yarım kalmış aktarım oluşmaz.

Adım 8: Form donmadan uzun sorgu nasıl çalıştırılır?

Rapor gibi uzun süren sorgular arayüz iş parçacığında çalışırsa form beyazlar ve Yanıt Vermiyor uyarısı çıkar. Sorguyu arka planda çalıştırıp sonucu ekrana yazmak bu sorunu çözer:

private async void btnRapor_Click(object sender, EventArgs e)
{
    btnRapor.Enabled = false;
    Cursor = Cursors.WaitCursor;
    try
    {
        DataTable tablo = await Task.Run(() =>
        {
            using var baglanti = Db.Ac();
            using var komut = baglanti.CreateCommand();
            komut.CommandText = @"SELECT substr(eklenme, 1, 7) AS Ay, COUNT(*) AS Adet
                                  FROM musteriler GROUP BY Ay ORDER BY Ay DESC";
            using var okuyucu = komut.ExecuteReader();
            var t = new DataTable();
            t.Load(okuyucu);
            return t;
        });

        dgvListe.DataSource = tablo;
    }
    finally
    {
        Cursor = Cursors.Default;
        btnRapor.Enabled = true;
    }
}

Dikkat edilmesi gereken nokta, Task.Run içinde form kontrollerine dokunmamaktır. Sorgu arka planda çalışır, DataGridView ataması await sonrasında yine arayüz iş parçacığında yapılır.

Veritabanı yedeği nasıl alınır?

Uygulama açıkken .db dosyasını Windows ile kopyalamak, yazma işlemi sürüyorsa bozuk bir yedek üretebilir. Microsoft.Data.Sqlite içindeki BackupDatabase metodu, uygulama çalışırken bile tutarlı bir kopya alır:

private void btnYedekAl_Click(object sender, EventArgs e)
{
    using var kaydet = new SaveFileDialog
    {
        Filter = "SQLite veritabanı|*.db",
        FileName = $"musteri-yedek-{DateTime.Now:yyyyMMdd-HHmm}.db"
    };
    if (kaydet.ShowDialog() != DialogResult.OK) return;

    using var kaynak = Db.Ac();
    using var hedef = new SqliteConnection($"Data Source={kaydet.FileName}");
    hedef.Open();
    kaynak.BackupDatabase(hedef);

    MessageBox.Show("Yedek başarıyla alındı.", "Bilgi");
}

Tablo yapısı sonradan nasıl güncellenir?

Uygulamanın yeni sürümünde tabloya sütun eklemeniz gerektiğinde kullanıcıların veritabanını silip yeniden oluşturamazsınız. SQLite dosyasının içinde tutulan user_version değeri, hangi güncellemelerin yapıldığını takip etmek için idealdir. Aşağıdaki metodu Hazirla metodunun sonunda çağırabilirsiniz:

private static void SemaGuncelle(SqliteConnection baglanti)
{
    using var oku = baglanti.CreateCommand();
    oku.CommandText = "PRAGMA user_version";
    long surum = (long)oku.ExecuteScalar()!;

    if (surum < 1)
    {
        using var komut = baglanti.CreateCommand();
        komut.CommandText = @"ALTER TABLE musteriler ADD COLUMN eposta TEXT;
                              PRAGMA user_version = 1;";
        komut.ExecuteNonQuery();
    }

    // Sonraki güncelleme: if (surum < 2) { ... PRAGMA user_version = 2; }
}

Her yeni sürümde sadece bir blok eklersiniz. Uygulama hangi sürümden güncellenirse güncellensin, eksik adımları sırayla tamamlar.

Sahadan notlar: Fabrika uygulamalarında SQLite

Fabrikada yazdığımız masaüstü uygulamalarda SQLite en çok tampon veritabanı olarak işimize yarıyor. Ağdaki ana sunucuya bağlanan bir uygulama, bağlantı koptuğunda veriyi kaybetmemek için önce yerel SQLite dosyasına yazıyor ve bağlantı geldiğinde ana veritabanına aktarıyor. Personel giriş çıkış verisinin aktarımı için planladığımız yapı da bu mantığa dayanıyor: Veri önce yerelde güvenceye alınıyor, ana veritabanına yazıldığı doğrulanmadan kaynaktan silinmiyor.

Çok eski makinelerde ise ayrı bir değerlendirme gerekiyor. Windows 7 çalışan ve yalnızca .NET Framework 3.5 kurulabilen bir kantar bilgisayarında, native SQLite kütüphanesinin işlemci mimarisi ve çalışma zamanı uyumu ek bir risk kalemi olarak karşımıza çıktı. Saklanacak veri çok küçükse ve makine eskiyse, basit bir dosya tabanlı kayıt da yeterli olabilir. SQLite her durumda doğru cevap değildir, ama yerel ve yapılandırılmış veri için çoğu zaman en iyi cevaptır.

Sık karşılaşılan hatalar ve çözümleri

Hata Sebep Çözüm
SQLite Error 1: no such table Uygulama farklı bir klasörde yeni ve boş bir veritabanı oluşturmuş Göreli yol yerine tam yol kullanın, Hazirla metodunun çalıştığından emin olun
database is locked Açık kalan bir bağlantı veya okuyucu dosyayı kilitliyor Bağlantıları using ile kapatın, busy_timeout ayarlayın
Yedek dosyası silinemiyor veya taşınamıyor Bağlantı havuzu dosyayı açık tutuyor İşlem sonrası SqliteConnection.ClearAllPools() çağırın
attempt to write a readonly database Veritabanı Program Files gibi yazma izni olmayan bir klasörde Dosyayı LocalApplicationData klasörüne taşıyın
e_sqlite3 yüklenemedi hatası Native kütüphane yayın klasörüne kopyalanmamış Yayın ayarlarında doğru platformu seçin, tek dosya yayında native kütüphaneleri pakete dahil edin
Türkçe aramada kayıt bulunamıyor LIKE yalnızca İngilizce harflerde büyük küçük harf duyarsız Türkçe küçük harfe çevrilmiş ayrı arama sütunu kullanın

Sıkça Sorulan Sorular

SQLite ile kaç kayıt saklanabilir?

SQLite milyonlarca kaydı rahatlıkla taşır ve veritabanı boyutu teorik olarak terabayt seviyesine çıkabilir. Masaüstü uygulamalarda asıl belirleyici kayıt sayısı değil, doğru index kullanımı ve ekrana getirilen kayıt sayısının sınırlanmasıdır.

SQLite veritabanını ağdaki ortak klasörde paylaşabilir miyim?

Önerilmez. Ağ paylaşımları üzerinden dosya kilitleme güvenilir çalışmadığı için birden fazla bilgisayar aynı anda yazdığında veritabanı bozulabilir. Çok kullanıcılı senaryolarda MySQL veya SQL Server gibi sunucu tabanlı bir veritabanı kullanın.

Microsoft.Data.Sqlite ile System.Data.SQLite arasındaki fark nedir?

İkisi de aynı SQLite motorunu kullanır. Microsoft.Data.Sqlite modern .NET projeleri için hafif ve güncel bir seçenektir. System.Data.SQLite ise DataAdapter desteği sunar ve eski .NET Framework projelerinde daha yaygındır.

SQLite veritabanına şifre koyabilir miyim?

Standart SQLite dosya şifrelemesi sunmaz. Şifreleme için SQLCipher tabanlı paketler kullanılabilir. Daha basit ihtiyaçlarda yalnızca hassas sütunları uygulama içinde şifreleyip kaydetmek de bir yöntemdir.

Veritabanı dosyasını hangi programla açıp inceleyebilirim?

Ücretsiz DB Browser for SQLite programı tabloları görmek, sorgu çalıştırmak ve veri düzeltmek için yeterlidir. Uygulamanız açıkken dosyada değişiklik yaparken dikkatli olun ve önce yedek alın.

WinForms uygulaması SQLite ile tek exe olarak dağıtılabilir mi?

Evet. Tek dosya yayın ayarında native kütüphanelerin pakete dahil edilmesi gerekir. Bu konuyu serinin bir sonraki yazısı olan tek exe yayınlama rehberinde ayrıntılı anlatıyoruz.

Ramazan Yeşildal
Ramazan Yeşildal

Karaman merkezli bilgi teknolojileri yöneticisi ve bağımsız yazılım geliştirici.

0 Yorum

Yorum yazın

E-posta adresiniz yayınlanmaz. Yorumlar onaydan sonra görünür.