.Net 5 Ef Core Kullanımı
12-08-20211. Eager Loading ve Where Kullanımı:
IQueryable<Category> cats = db.Categories .Include(c => c.Products.Where(p => p.Stock >= stock));
Not: RawSql görmek için ToQueryString() metodu kullanılır.
2. SQL Yorumu:
IQueryable<Product> prods = db.Products .TagWith("Products filtered by price and sorted.") .Where(product => product.Cost > price) .OrderByDescending(product => product.Cost);
Şu şekilde SQL yorumu ekler:
-- Products filtered by price and sorted.
3. Like Query:
IQueryable<Product> prods = db.Products .Where(p => EF.Functions.Like(p.ProductName, $"%{input}%"));
4. LoggerFactory Kullanımı
using (var db = new NorthwindContext()) { var loggerFactory = db.GetService<ILoggerFactory>(); loggerFactory.AddProvider(new ConsoleLoggerProvider()); }
5. Global Filter:
protected override void OnModelCreating(ModelBuilder modelBuilder) { // example of using Fluent API instead of attributes // to limit the length of a category name to under 15 modelBuilder.Entity<Category>() .Property(category => category.CategoryName) .IsRequired() // NOT NULL .HasMaxLength(15); // added to "fix" the lack of decimal support in SQLite modelBuilder.Entity<Product>() .Property(product => product.Cost) .HasConversion<double>(); // global filter to remove discontinued products modelBuilder.Entity<Product>().HasQueryFilter(p => !p.Discontinued); }
6. Lazy Loading için:
-<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="5.0.0" />
- optionsBuilder.UseLazyLoadingProxies().UseSqlite($"Filename={path}");
- Include metodu kullanılmaz. Category içerisindeki products loop ile çağrıldığı zaman lazy olarak yüklenecektir.
- Lazy disable yapmak için:db.ChangeTracker.LazyLoadingEnabled = false;
7. Explicitly Loading:
var products = db.Entry(c).Collection(c2 => c2.Products); //buradaki c bir Category nesnesi if (!products.IsLoaded) products.Load(); WriteLine($"{c.CategoryName} has {c.Products.Count} products.");
8. Veri Ekleme
static bool AddProduct( int categoryID, string productName, decimal? price) { using (var db = new Northwind()) { var newProduct = new Product { CategoryID = categoryID, ProductName = productName, Cost = price }; // mark product as added in change tracking db.Products.Add(newProduct); // save tracked change to database int affected = db.SaveChanges(); return (affected == 1); } }
9. Veri Güncelleme
static bool IncreaseProductPrice(string name, decimal amount) { using (var db = new Northwind()) { // get first product whose name starts with name Product updateProduct = db.Products.First( p => p.ProductName.StartsWith(name)); updateProduct.Cost += amount; int affected = db.SaveChanges(); return (affected == 1); } }
10. Veri Silme
static int DeleteProducts(string name) { using (var db = new Northwind()) { IEnumerable<Product> products = db.Products.Where(p => p.ProductName.StartsWith(name)); db.Products.RemoveRange(products); // tek kayıt silmek için Remove kullanılır int affected = db.SaveChanges(); return affected; } }
11. Connection Pooling
Normalde DbContext sınıfı disposable özelliğe sahiptir. using keywordu ile kullanıldığı zaman işlem bitince disposable metodu otomatik olarak çağrılır. Connection Pooling için şu kodu kullanabiliriz:
services.AddDbContextPool<BloggingContext>( options => options.UseSqlServer(connectionString));
Bu kod kullanıldığı zaman disposable metodu çağrıldığı zaman bağlantı havuzuna geri döner. Fakat burada dikkat edilmesi gereken husus şudur: Eğer OnConfiguring içerisinde ortak paylaşılamayacak bir private field varsa bu mekanizma kullanılmamalıdır.
12. Transactions Kullanımı
- Öncelikle IDbContextTransaction sınıfını kullanmak için "using Microsoft.EntityFrameworkCore.Storage;"
statement eklenir.
- Database Context sınıfının Database property si kullanılır.
- Örnek:
static int DeleteProducts(string name) { using (var db = new Northwind()) { using (IDbContextTransaction t = db.Database.BeginTransaction()) { WriteLine("Transaction isolation level: {0}", t.GetDbTransaction().IsolationLevel); var products = db.Products.Where( p => p.ProductName.StartsWith(name)); db.Products.RemoveRange(products); int affected = db.SaveChanges(); t.Commit(); return affected; } } }
Bu kod çalıştığı zaman şu output olur: Transaction isolation level: Serializable yazar. Bu leveli değiştirmek için DbContext.Database.BeginTransaction(IsolationLevel.Snapshot); metodu kullanılır.
13. Linq Kullanımı
DbSet<T>
sınıfı IQueryable<T>
interface'ini, bu interface ise IEnumerable<T>
interface'ini implement ettiği için Linq kütüphanesi EF Core ile kullanılabilmektedir.
Memory üzerinde LINQ provider ile query'ler oluşturulmaktadır. Bu işlem expression tree mantığı ile yapılmaktadır. "Expression tree" Kodu ağaç benzeri bir veri yapısında temsil ederler ve SQLite gibi harici veri sağlayıcıları için LINQ sorguları oluşturmak için yararlı olan dinamik sorguların oluşturulmasını sağlarlar.
a. Sadece belli sütunları çekmek
Projection yapısı kullanılmaktadır.
var query = db.Products // query is a DbSet<Product> .Where(product => product.UnitPrice < 10M) // query is now an IQueryable<Product> .OrderByDescending(product => product.UnitPrice) // query is now an IOrderedQueryable<Product> .Select(product => new // anonymous type projection usage { product.ProductID, product.ProductName, product.UnitPrice });
b. Include kullanmadan iki tabloyu birleştirmek
Aşağıdaki gibi JOIN metodunu kullanabiliriz. Bu metod 4 parametre almaktadır.birleştirmek istediğiniz dizi, eşleştirilecek sol dizideki özellik veya özellikler, eşleştirilecek sağ dizideki özellik veya özellikler ve bir projection.
static void JoinCategoriesAndProducts() { using (var db = new Northwind()) { // join every product to its category to return 77 matches var queryJoin = db.Categories.Join( inner: db.Products, outerKeySelector: category => category.CategoryID, innerKeySelector: product => product.CategoryID, resultSelector: (c, p) => new { c.CategoryName, p.ProductName, p.ProductID }); foreach (var item in queryJoin) { WriteLine("{0}: {1} is in {2}.", arg0: item.ProductID, arg1: item.ProductName, arg2: item.CategoryName); } } }
c. Grup ve Join kullanımı ise aşağıdaki gibi yapılabilir:
static void GroupJoinCategoriesAndProducts() { using (var db = new Northwind()) { // group all products by their category to return 8 matches var queryGroup = db.Categories.AsEnumerable().GroupJoin( inner: db.Products, outerKeySelector: category => category.CategoryID, innerKeySelector: product => product.CategoryID, resultSelector: (c, matchingProducts) => new { c.CategoryName, Products = matchingProducts.OrderBy(p => p.ProductName) }); foreach (var item in queryGroup) { WriteLine("{0} has {1} products.", arg0: item.CategoryName, arg1: item.Products.Count()); foreach (var product in item.Products) { WriteLine($" {product.ProductName}"); } } } }
AsEnumerable
metodu kullanılmasaydı RuntimeException meydana gelirdi.
Bu iki yöntemin kullanılma amacı birbiriyle foreign keyi bağlantısı olmayan tabloların birleştirilmesini sağlamaktır.
d. Kendi LINQ metodumuzu oluşturmak:
using System.Collections.Generic; namespace System.Linq // extend Microsoft's namespace { public static class MyLinqExtensions { // this is a chainable LINQ extension method public static IEnumerable<T> ProcessSequence<T>( this IEnumerable<T> sequence) { // you could do some processing here return sequence; } // these are scalar LINQ extension methods public static int? Median(this IEnumerable<int?> sequence) { var ordered = sequence.OrderBy(item => item); int middlePosition = ordered.Count() / 2; return ordered.ElementAt(middlePosition); } public static int? Median<T>( this IEnumerable<T> sequence, Func<T, int?> selector) { return sequence.Select(selector).Median(); } public static decimal? Median( this IEnumerable<decimal?> sequence) { var ordered = sequence.OrderBy(item => item); int middlePosition = ordered.Count() / 2; return ordered.ElementAt(middlePosition); } public static decimal? Median<T>( this IEnumerable<T> sequence, Func<T, decimal?> selector) { return sequence.Select(selector).Median(); } public static int? Mode(this IEnumerable<int?> sequence) { var grouped = sequence.GroupBy(item => item); var orderedGroups = grouped.OrderByDescending( group => group.Count()); return orderedGroups.FirstOrDefault().Key; } public static int? Mode<T>( this IEnumerable<T> sequence, Func<T, int?> selector) { return sequence.Select(selector).Mode(); } public static decimal? Mode( this IEnumerable<decimal?> sequence) { var grouped = sequence.GroupBy(item => item); var orderedGroups = grouped.OrderByDescending( group => group.Count()); return orderedGroups.FirstOrDefault().Key; } public static decimal? Mode<T>( this IEnumerable<T> sequence, Func<T, decimal?> selector) { return sequence.Select(selector).Mode(); } } }
Daha sonra aşağıdaki gibi kullanabiliriz:
var query = db.Products // query is a DbSet<Product> .ProcessSequence() .Where(product => product.UnitPrice < 10M) // query is now an IQueryable<Product> .OrderByDescending(product => product.UnitPrice) // query is now an IOrderedQueryable<Product> .Select(product => new // anonymous type { product.ProductID, product.ProductName, product.UnitPrice });
Median, Average metodlarının kullanımı:
static void CustomExtensionMethods() { using (var db = new Northwind()) { WriteLine("Mean units in stock: {0:N0}", db.Products.Average(p => p.UnitsInStock)); WriteLine("Mean unit price: {0:$#,##0.00}", db.Products.Average(p => p.UnitPrice)); WriteLine("Median units in stock: {0:N0}", db.Products.Median(p => p.UnitsInStock)); WriteLine("Median unit price: {0:$#,##0.00}", db.Products.Median(p => p.UnitPrice)); WriteLine("Mode units in stock: {0:N0}", db.Products.Mode(p => p.UnitsInStock)); WriteLine("Mode unit price: {0:$#,##0.00}", db.Products.Mode(p => p.UnitPrice)); } }