Entity Framework Core Üzerinde DBSet Olmadan Raw SQL Query Yazma

Selamlar,

  Bu makalede, Entity Framework Core ile çalışırken, bazen Linq ile yazılmayacak kadar complex sorgular ile uğraşmanız gerekebilir. Bu gibi durumlarda kodların DB’de olmaması, test senaryoları ve  Debug yapılamaması yüzünden, View veya Procedurler tercih edilmeyebilir. Bu durumda, Entity Framework üzerinde Raw Sql Query yazmak, doğru bir seçenek olabilir.

İşin zor kısmı, bu makale itibari ile artık Entity Framework Core 3.1’de DBSet olmadan RawSql yazmak mümkün değildir. Kısaca artık dbData.Database.SqlQuery<SomeModel> kaldırılmış, onun yerine her zaman kullanılması zorunlu olan DBSet<> getirilmiştir. dbData.Product.FromSql(“SQL SCRIPT”) gibi.

İşte bu makalede, Sql tarafında View, Procedure veya yeni bir tablo oluşturmadan, nasıl custom sorgular yazılabileceğini hep beraber inceleyeceğiz.

Öncelikle çekilmek istenen sorgu aşağıdaki gibidir: Amaç, Customer servisi altında Northwind database’i üzerinde en fazla miktarda sipariş veren 5 müşterinin listesinin çekilmesidir. “GetCustomerOrderByRawSql()” methodunda, 3 farklı tablodan gruplanıp,sıralanarak bir sorgu çekilmektedir. İlgili sorgunun sonucu, projede “Top5OrderModel” modelidir. Bu, bir çeşit bizim ViewModelimizdir. Aşağıdaki CustomService, geriye ServiceResponse model dönmektedir. ServiceResponse modelinin List property’sine, sorgudan dönen “List<Top5OrderModel>()” değeri atanmaktadır.

Services/Customers/CustomerService:

Services/Customers/ICustomerService: Aşağıda görüldüğü gibi  CustomerService, GetCustomerOrderByRawSql() methoduna zorlanmıştır.

Servisden dönen JsonResult:

Core/ApiResponse/ServiceResponse: Tüm servisler, aşağıda görüldüğü gibi ServiceResponse tipinde ortak bir model döner. Burada önemli olan “List” List of <T> tipinde Top5OrderModel dönülür. Tek bir model dönülse, Entity tipinde dönülmektedir. Token, RefreshToken, CreatedTokenTime authentication amaçlı kullanılan alanlardır.

Core/Models/Customer/Top5OrderModel: Sorgu sonucu ihtiyac duyulan ViewModel, aşağıdaki gibidir. Ama gerçekte, DB tarafında böyle bir tablo bulunmamaktadır. Ve oluşturulmayacaktır.

Şimdi sıra geldi, bu modeli DBFirst ile oluşan Context’de tanımlamaya. Tabi ki DB’den komut ile oluşan NorthwindContex’e, bir tanımlama yapılmayacaktır. Çünkü yapılan tanımlama, tekrar komutun çalıştırılması ile ezilecektir.

    • İlgili Komut: “dotnet ef dbcontext scaffold “Server=localhost\SQLEXPRESS;Database=Northwind;Trusted_Connection=True;” Microsoft.EntityFrameworkCore.SqlServer –output-dir Entities –force

DB/PartialEntites/DBContext: Aşağıda görüldüğü gibi “DBContext“, NorthwindContext’den türetilmiştir. Böylece bu kod üzerinde yapılan değişiklikler, “dotnet ef dbcontext scaffold” komutu ile yeniden oluşan DBContext ve DBSetler ile üzerine ezilmemiş olunur.

  • “public DbSet<Top5OrderModel> Top5OrderModel { get; set; }” : Top5OrderModel model sanki DB’den var olan bir tablo gibi tanımlanır. Bu aslında, sahte bir modeldir. Ne DB’de yaratılacaktır. Ne de zaten vardır. Tek amacı, Raw Sql şeklinde yazılan sorgudan dönen soncu, karşılamaktır.
  • *“modelBuilder.Entity<Top5OrderModel>(entity => { entity.HasNoKey(); })” : OnModelCreating() methodunda, yaratılan Top5OrderModel DBSet’inin bir keyinin olmadığının tanımlanması gerekmektedir. Aksi takdirde Index Hatası alınır.
    • Not: HasNoKey tanımlaması, tüm Viewlar için de yapılmalıdır.

Şimdi sıra geldi, CustomerService’indeki “Top5CustomerOrder()” methodunu, CustomerController’dan çağırmaya.

Bu makalede, farklı tablolardan Raw Sql Query ile data çeken bir servisin, .Net Core Entity 3.1’de nasıl yazılabileceğini hep beraber inceledik. Normal şartlar altında pek de tercih edilmemesi gereken bu yöntem, çok kompleks querylerde linq yazmak yerine kullanılabilir. Son olarak bunun yerine, Sql tarafında bir View oluşturulup, DB First ile oluşturulan bu View, projeye “DBSet<>” olarak generate edilebilir. Ve çekilmek istenen query, bu view üzerinden yapılabilir. Ama tabi ki bu da, hem Database katmanında, hem de kod tarafında ayrı ayrı çalışma yapılmasını gerektirmektedir. Eğer bir rapor projesi yazılıyor ise, herbir kompleks query için, ayrı ayrı View oluşturmak hem çok mantıklı değil hem de performans açısından tercih edilmeyebilir.

Geldik bir makalenin daha sonuna. Yeni bir makalede görüşmek üzere, hepinize hoşçakalın.

Source:

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir