FmgLib.Orm.DbHelper

Son Güncellenme: 08 Eyl 2024

FmgLib.Orm.DbHelper

DbHelper, .NET için mikro ORM kütüphanesidir. MySql, PostgreSql, Oracle, SqlServer, SQLite gibi veri tabanı türlerini desteklemektedir. First Code yaklaşımı ile veritabanı oluşturulması desteği bulunmaktadır ancak sadece Oracle veritabanı için bu geçerli değildir. DbHelper sizlere birden fazla veritabanı desteği sağlamaktadır. Aynı sorgu yapısını basit bir şekilde diğer veritabanı türleri için uygulama imkanı sunmaktadır.

FmgLib.Orm.DbHelper linkinden nuget paketine ulaşabilirsiniz.

DbHelper kütüphanesini projenize dahil etmek için nuget üzerinden hangi veritabanı ile devam edecekseniz ilgili kütüphaneyi indirmeniz gerekmektedir. Örneğin: FmgLib.Orm.DbHelper.MySql, FmgLib.Orm.DbHelper.PostgreSql, FmgLib.Orm.DbHelper.SqlServer, FmgLib.Orm.DbHelper.SQLite, FmgLib.Orm.DbHelper.Oracle bu kütüphanelerden hangisi ile çalışmak istiyorsanız son sürümü indirerek projenize dahil edebilirsiniz.

Öncelikle veritabanı tarafındaki tabloya ait modeli oluşturalım(First-code yaklaşımı olması bişey değiştirmez);

using FmgLib.Orm.Common;

namespace FmgLib.TestWeb.Models;

[Table("PRODUCTS")]
public class Product : IDbEntity
{
    [Column(IsNotNull = true, IsPrimaryKey = true, IsAutoIncrement = true)]
    public int Id { get; set; }

    [Column(IsNotNull = true)]
    public string ProductName { get; set; }

    [Column(IsNotNull = false)]
    public double Price { get; set; }

    public int? CategoryId { get; set; }
}

[Table("CATEGORIES")]
public class Category : IDbEntity
{
    [Column(true,true,true)]
    public int Id { get; set; }
    public string Name { get; set; }

    public int? SubCategoryId { get; set; }
    public SubCategory? SubCategory { get; set; }
}

[Table("SUBCATEGORIES")]
public class SubCategory : IDbEntity
{
    [Column(true, true, true)]
    public int Id { get; set; }
    public string Name { get; set; }
}

Burada bazı incelikler bulunmaktadır:

  • Class üzerine Table("TABLE_NAME") şeklinde kullanıp veritabanı tarafında oluşacak tabloya özel isim verilebilir. Eğer ki verilmezse default olarak Class name yani sınıf adı verilir.
  • Column([bool IsNotNull = false], [bool IsPrimaryKey = false], [bool IsAutoIncrement = false]) ile property için tablo tarafında özelleştirmeler yapılabilir. IsNotNull ile nullable özelliği kontrol edilir. Primary Key özelliği ve Otomatik artan gibi özellikler bu attribute ile kontrol edilir. bir sütunun nullable olmasını kontrol etmek için özellikle Column attribute kullanılmasına gerek yoktur. değer tipinden sonra ? karakteri ile nullable özelliği sağlanabilir.
  • Buradaki en önemli husus modelin IDbEntity türünden türemesidir. Bu yapılmaz ise model veritabanı tarafında oluşturulmaz.

Şimdi gelelim projeye ilgili kütüphaneyi entegre etmeye, bunun için Program.cs dosyasında gerekli entegrasyonlar yapılır:

using FmgLib.Orm.DbHelper.MySql;
using FmgLib.Orm.DbHelper.PostgreSql;
using FmgLib.Orm.DbHelper.SQLite;
using FmgLib.Orm.DbHelper.SqlServer;
using FmgLib.Orm.DbHelper.Oracle;

var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();

await builder.Services.DbEntegrationMySqlAsync(builder.Configuration.GetConnectionString("MYSQL")); // OR
// builder.Services.DbEntegrationMySql(builder.Configuration.GetConnectionString("MYSQL")); // Asynchronous and synchronous usage is up to your preference.

await builder.Services.DbEntegrationPostgreSqlAsync(builder.Configuration.GetConnectionString("POSTGRESQL")); // OR
// builder.Services.DbEntegrationPostgreSql(builder.Configuration.GetConnectionString("POSTGRESQL")); // Asynchronous and synchronous usage is up to your preference.

await builder.Services.DbEntegrationSQLiteAsync(builder.Configuration.GetConnectionString("SQLITE")); // OR
// builder.Services.DbEntegrationSQLite(builder.Configuration.GetConnectionString("SQLITE")); // Asynchronous and synchronous usage is up to your preference.

await builder.Services.DbEntegrationSqlServerAsync(builder.Configuration.GetConnectionString("SQLSERVER")); // OR
// builder.Services.DbEntegrationSqlServer(builder.Configuration.GetConnectionString("SQLSERVER")); // Asynchronous and synchronous usage is up to your preference.

await builder.Services.DbEntegrationOracleAsync(builder.Configuration.GetConnectionString("ORACLE")); // OR
// builder.Services.DbEntegrationOracle(builder.Configuration.GetConnectionString("ORACLE")); // Asynchronous and synchronous usage is up to your preference.

var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

DbEntegrationMySql(CONN_STR), DbEntegrationPostgreSql(CONN_STR), DbEntegrationSqlServer(CONN_STR), DbEntegrationSQLite(CONN_STR), DbEntegrationOracle(CONN_STR) fonksiyonları veritabanı entegrasyonunu ve oluşturulmuş modellerimizi veritabanı tarafında tablo olarak oluşturur. Her yeni model eklendiğinde program tekrardan çalıştırıldığında bu fonksiyon tetikleneceği için yeni tablolar veritabanında otomatik oluşturulur. Entegrasyon kısmı bu kadar basit şekilde tamamlanabilir durumda.

Örnek kullanımlara bakacaksak olursak: Öncelikle örneklerimizi Query ve Command şeklinde iki kısmında değerlendirip ardından veritabanı türlerine göre nasıl değişkenlik gösterdiğini gösterelim.

  • Query için: Query.GetQuery<TEntity>() şeklinde query oluşturmuş oluyoruz. Devamında query için özel konutlar eklenebilir.
using FmgLib.Orm.DbHelper;

var query = Query.GetQuery<Product>() // Query oluşturuldu.
                .Include(x => x.Category) // Category Tablosu Eklendi (Product modelinin Category özelliğine veriler eklendi).
                .ThenInclude(x => x.SubCategory) // SubCategory Tablosu Eklendi (Category modelinin SubCategory özelliğine veriler eklendi).
	            .Where(x => x.Price > 250 && x.ProductName.Contains("Dene")) // filtreleme işlemi yapıldı.
                .DistinctBy(x => x.Price) // Distinct için sütun eklendi.
                .DistinctBy(x => x.ProductName) // Distinct için sütun eklendi.
                .Select(x => x.CategoryId) // Select için sütun eklendi.
                .OrderBy(x => x.Id) // Sıralama eklendi (Küçükten büyüğe doğru).
                .OrderByDescending(x => x.Price); // Sıralama eklendi (Büyükten küçüğe doğru).

SQL'de bazı kurallar nedeniyle burada oluşturacağınız tüm sorgular SQL sorgu mantığı için süzülüp uygulanır. Yani şöyle ki bir sorgu sonucunda Max değeri almak istiyorsunuz veyahut ilgili sütunun toplam değerini almak istiyorsanız ORDER BY kullanımı yanlış olacaktır. Burada SqlBuilder katmanı gerekli işlemleri yapıp sorgunuzun başarılı bir şekilde mantığı bozulmadan çalışmasını sağlar. İlgili query oluşturulduktan sonra hangi veritabanına istek göndereceğimiz bize kalmıştır. Yani koda şu şekilde devam edebiliriz:

using FmgLib.Orm.DbHelper.MySql;
using FmgLib.Orm.DbHelper.PostgreSql;
using FmgLib.Orm.DbHelper.SQLite;
using FmgLib.Orm.DbHelper.SqlServer;
using FmgLib.Orm.DbHelper.Oracle;

/*
var queryMySql = query.AsQueryMySql(); // query MySql yapısına geçti.
var queryPostgreSql = query.AsQueryPostgreSql(); // query PostgreSql yapısına geçti.
var querySqlServer = query.AsQuerySqlServer(); // query SqlServer yapısına geçti.
var querySQLite = query.AsQuerySQLite(); // query SQLite yapısına geçti.
var queryOracle = query.AsQueryOracle(); // query Oracle yapısına geçti.
*/
// Buradan sonra SqlServer ile devam edilecektir. Bundan sonraki tüm adımlar diğer veri tabanı türlerinde de aynı olduğundan dolayı aralarındaki fark verilip devam edilmiştir.
// Bundan sonraki adımlarda hangi veritabanı ile devam etmek istiyorsanız:
// AsQueryMySql() yerine o metodu çağırmanız yeterlidir. Metodlar yukarıda verilmiştir.

// AsQuerySqlServer() -> SqlServer
// AsQuerySQLite() -> SQLite
// AsQueryPostgreSql() -> PostgreSql
// AsQueryOracle() -> Oracle
// AsQueryMySql() -> MySql

var qqqq = query.AsQuerySqlServer().First(); // İlk kaydı getirir.
var wwww = query.AsQuerySqlServer().First(x => x.Id > 10); // Önceki Filter üstüne içindeki filter ile ilk kaydı getirir.
var eeee = query.AsQuerySqlServer().FirstOrDefault(); // İlk kaydı getirir yoksa default oluşturur.
var rrrr = query.AsQuerySqlServer().FirstOrDefault(x => x.Id > 10); // Önceki Filter üstüne içindeki filter ile ilk kaydı getirir yoksa default oluşturur.
var tttt = query.AsQuerySqlServer().ElementAt(5); // 5. sıradaki kaydı getirir.
var yyyy = query.AsQuerySqlServer().ElementAtOrDefault(5); // 5. sıradaki kaydı getirir yoksa default oluşturur.
var uuuu = query.AsQuerySqlServer().Min(x => x.Price); // parametre olarak aldığı ilgili sütundaki minimum değeri geriye döner.
var cccc = query.AsQuerySqlServer().MinBy(x => x.Price); // parametre olarak aldığı ilgili sütundaki minimum değerdeki kaydı geriye döner.
var oooo = query.AsQuerySqlServer().Max(x => x.Price); // parametre olarak aldığı ilgili sütundaki maksimum değeri geriye döner.
var pppp = query.AsQuerySqlServer().MaxBy(x => x.Price); // parametre olarak aldığı ilgili sütundaki maksimum değerdeki kaydı geriye döner.
var llll = query.AsQuerySqlServer().Sum(x => x.Price); // parametre olarak aldığı ilgili sütundaki verilerin toplamını geriye döner.
var zzzz = query.AsQuerySqlServer().Average(x => x.Price); // parametre olarak aldığı ilgili sütundaki verilerin ortalamasını geriye döner.
var aaaa = query.AsQuerySqlServer().Count(); // kayıt sayısını geriye döner.
var ssss = query.AsQuerySqlServer().Count(x => x.Price < 600); // Önceki Filter üstüne içindeki filter ile kayıt sayısını geriye döner.
var dddd = query.AsQuerySqlServer().Any(); // kayıt var mı yok mu değerini verir. (true/false)
var ffff = query.AsQuerySqlServer().Any(x => x.Price < 600); // Önceki Filter üstüne içindeki filter ile beraber kayıt var mı yok mu değerini verir. (true/false)
var gggg = query.AsQuerySqlServer().Skip(20); // 20 kayıt atlayarak geri kalan verileri getirir.
var hhhh = query.AsQuerySqlServer().Take(20); // İlk 20 kayıt geriye döndürülür.
var xxxx = query.AsQuerySqlServer().SkipAndTake(10, 20); // 10. kayıttan itibaren 20 kayıt geriye döner.
var kkkk = query.AsQuerySqlServer().ToList(); // kayıtları liste şeklinde geriye döner.
var xxxx = query.AsQuerySqlServer().ToArray(); // kayıtları dizi şeklinde geriye döner.
var vvvv = query.AsQuerySqlServer().ToQuery(); // kayıtları IQueryable şeklinde geriye döner.
var bbbb = query.AsQuerySqlServer().ToQuery("SELECT * FROM PRODUCTS ORDER BY Price DESC"); // Önceki sorgulardan bağımsız olarak içerisine parametre olarak aldığı sql sorgusunun sonucunda gelen veriyi IQueryable şeklinde geriye döner.

// bu metodların Async türleri de mevcuttur.
  • Command için:

// Örnek olarak SqlServer ile devam edilmiştir. Diğer veri tabanları için AsCommandSqlServer() metodu yerine ilgili metodu kullanabilirsiniz. Geri kalan süreçlerde değişiklik bulunmamaktadır. 
// AsCommandSqlServer() -> SqlServer
// AsCommandSQLite() -> SQLite
// AsCommandPostgreSql() -> PostgreSql
// AsCommandOracle() -> Oracle
// AsCommandMySql() -> MySql

var insertr = Command
                .Insert(new Product
                {
                    ProductName = "One item insert test",
                    Price = 1234,
                    CategoryId = 234
                }) // insert komudu oluşturuldu.
                .AsCommandSqlServer() // komut SqlServer'a aktarıldı.
                .Save(); // komut veritabanına işlendi. Geriye int değer döndü.
                
var insertrMulti = Command
                .InsertRange(/*products list*/) // liste gönderilerek birden fazla insert komudu oluşturulur.
                .AsCommandSqlServer() // komut SqlServer'a aktarıldı.
                .Save(); // komut veritabanında işlendi. Geriye int değer döndü.
                
var updater = Command
                .Update(new Product
                {
                    ProductName = "222 TEST DENEME 22",
                    Price = 6134,
                    CategoryId = 155
                }, x => x.Id == 102) // filter ile beraber update komudu oluşturuldu.
                .AsCommandSqlServer() // komut SqlServer'a aktarıldı.
                .Save(); // komut veritabanında işlendi. Geriye int değer döndü.

var deleter = Command
                .Delete<Product>(x => x.Id == 102) // filter ile beraber delete komudu oluşturuldu.
                .AsCommandSqlServer() // komut SqlServer'a aktarıldı.
                .Save(); // komut veritabanında işlendi. Geriye int değer döndü.
                
// Save() metodunun Async türü de mevcuttur. SaveAsync() şeklinde kullanılabilir.