.Net 5 Ef Core Kullanımı

12-08-2021

1. 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));
  }
}

© 2019 All rights reserved. Codesenior.COM