EF Core (Entity Framework Core) 9 adalah ORM framework versi terbaru yang disempurnakan yang ditujukan untuk pengembangan aplikasi berbasis .NET sehingga pengembang dapat bekerja dan mengembangkan aplikasi dalam lingkungan object/class berbasis .NET . Salah satu fitur yang paling berguna dari EF Core 9 adalah kemampuan menggunakan Sql Raw Query untuk dimapping langsung ke dalam class .NET atau class model yang telah kita buat. Fitur ini sangat berguna ketika kita memiliki query untuk mengakses data, namun hasil query ini nama kolom kolomnya tidak cocok terhadap struktur tabel manapun di database, sehingga kita memiliki hasil query sql yang memang harus dimapping ke dalam class khusus yang strukturnya sesuai dengan kolom kolom hasil query sql.
Dengan menggunakan database AdventureWorks2022 dan server MSSQL yang telah ada, kita coba query sql sederhana berikut ini
SELECT so.[SalesOrderID]
,so.[OrderDate]
,so.[PurchaseOrderNumber]
,so.[CustomerID]
,p.FirstName+' '+p.LastName as CustomerName
,t.CountryRegionCode + '-' + t.Name as Region
,isnull(a.AddressLine1,'') + ' ' + isnull(a.AddressLine2,'') + ' ' + isnull(a.City,'') + ', '+ isnull(a.PostalCode,'') as ShippingAddress
,sm.Name as ShippingMethod
,rcur.CurrencyCode
,so.[SubTotal]
,so.[TaxAmt]
,so.[Freight]
,so.[TotalDue]
FROM [Sales].[SalesOrderHeader] so
join [Sales].[Customer] c ON so.CustomerID=c.CustomerID
join [Person].[Person] p ON c.PersonID=p.BusinessEntityID
join [Sales].[SalesTerritory] t ON so.TerritoryID=t.TerritoryID
join [Person].[Address] a ON so.ShipToAddressID=a.AddressID
join [Purchasing].[ShipMethod] sm ON so.ShipMethodID=sm.ShipMethodID
join [Sales].[CountryRegionCurrency] rcur ON rcur.CountryRegionCode=t.CountryRegionCode
where
a.AddressLine1 is not null
and so.PurchaseOrderNumber is not null
Jika dieksekusi, maka query SQL tersebut akan menghasilkan data seperti pada Gambar 1 berikut ini

Kemudian bagaimanakah memapping query dan hasil query di atas supaya bisa diakses melalui .NET object dan entity framework? Jawabannya dengan menggunakan method SqlQueryRaw<TEntity>(sql).
Pertama kita perlu untuk membuat POCO class yang merepresentasikan entity dari hasil query tersebut di atas. Kita buat class bernama SalesModel di dalam folder Models dari project
namespace EF.Models
{
public class SalesModel
{
public int SalesOrderID { get; set; }
public DateTime? OrderDate { get; set; }
public string? PurchaseOrderNumber { get; set; }
public int CustomerID { get; set; }
public string? CustomerName { get; set; }
public string? Region { get; set; }
public string? ShippingAddress { get; set; }
public string? ShippingMethod { get; set; }
public string? CurrencyCode { get; set; }
public decimal? SubTotal { get; set; }
public decimal? TaxAmt { get; set; }
public decimal? Freight { get; set; }
public decimal? TotalDue { get; set; }
}
}

Setelah itu kita akan mengakses query dengan menggunakan SqlQueryRaw seperti berikut ini
using EF.AppDbContext;
using EF.Entities;
using EF.Models;
using Microsoft.EntityFrameworkCore;
namespace ConsoleApp123
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
var dbContext = new AppDbContext();
var sql = $@"
SELECT so.[SalesOrderID]
,so.[OrderDate]
,so.[PurchaseOrderNumber]
,so.[CustomerID]
,p.FirstName+' '+p.LastName as CustomerName
,t.CountryRegionCode + '-' + t.Name as Region
,isnull(a.AddressLine1,'') + ' ' + isnull(a.AddressLine2,'') + ' ' + isnull(a.City,'') + ', '+ isnull(a.PostalCode,'') as ShippingAddress
,sm.Name as ShippingMethod
,rcur.CurrencyCode
,so.[SubTotal]
,so.[TaxAmt]
,so.[Freight]
,so.[TotalDue]
FROM [Sales].[SalesOrderHeader] so
join [Sales].[Customer] c ON so.CustomerID=c.CustomerID
join [Person].[Person] p ON c.PersonID=p.BusinessEntityID
join [Sales].[SalesTerritory] t ON so.TerritoryID=t.TerritoryID
join [Person].[Address] a ON so.ShipToAddressID=a.AddressID
join [Purchasing].[ShipMethod] sm ON so.ShipMethodID=sm.ShipMethodID
join [Sales].[CountryRegionCurrency] rcur ON rcur.CountryRegionCode=t.CountryRegionCode
where a.AddressLine1 is not null
and so.PurchaseOrderNumber is not null
";
var top10Sales = dbContext.Database.SqlQueryRaw<SalesModel>(sql)
.OrderByDescending(m => m.TotalDue)
.Take(10)
.ToList();
Console.WriteLine("Top 10 sales :");
for (int i = 0; i < top10Sales.Count; i++)
{
int nomer = i + 1;
var sales = top10Sales[i];
Console.WriteLine($"{nomer}. {sales.OrderDate:dd/MM/yyyy} PO No. {sales.PurchaseOrderNumber} Customer {sales.CustomerName} Ship To {sales.ShippingAddress} with Total Due {sales.TotalDue:#,##0.00}");
}
}
}
}
Dan jika di running maka akan ditampilkan 10 penjualan dengan total pembelian terbesar.

Hal ini terjadi pada bagian kode program bagian di bawah ini yang mentranslasikan query sql ke object, melakukan sorting, dan mengambil 10 baris paling atas
var top10Sales = dbContext.Database.SqlQueryRaw<SalesModel>(sql)
.OrderByDescending(m => m.TotalDue)
.Take(10)
.ToList();