Alıştırma - Verilerle etkileşim kurma
Önceki alıştırmada varlık sınıfları ve veritabanı bağlamı oluşturdunuz. Ardından VERITABANı şemasını oluşturmak için EF Core geçişlerini kullandınız.
Bu alıştırmada uygulamayı tamamlaacaksınız PizzaService
. Hizmet, veritabanında CRUD işlemleri gerçekleştirmek için EF Core kullanır.
CRUD işlemlerini kodlama
Uygulamayı tamamlamak PizzaService
için Services\PizzaService.cs dosyasında aşağıdaki adımları tamamlayın:
Örnekte gösterildiği gibi aşağıdaki değişiklikleri yapın:
- Yönerge
using ContosoPizza.Data;
ekleyin. - Yönerge
using Microsoft.EntityFrameworkCore;
ekleyin. - Oluşturucudan önce için
PizzaContext
bir sınıf düzeyi alanı ekleyin. - Oluşturucu yöntemi imzasını parametre
PizzaContext
kabul etmek için değiştirin. - parametresini alana atamak için oluşturucu yöntem kodunu değiştirin.
using ContosoPizza.Models; using ContosoPizza.Data; using Microsoft.EntityFrameworkCore; namespace ContosoPizza.Services; public class PizzaService { private readonly PizzaContext _context; public PizzaService(PizzaContext context) { _context = context; } /// ... /// CRUD operations removed for brevity /// ... }
AddSqlite
Bağımlılık ekleme için daha önce program.cs dosyasınaPizzaContext
eklediğiniz yöntem çağrısı.PizzaService
Örnek oluşturulduğunda oluşturucuya birPizzaContext
eklenir.- Yönerge
GetAll
yöntemini aşağıdaki kod ile değiştirin:public IEnumerable<Pizza> GetAll() { return _context.Pizzas .AsNoTracking() .ToList(); }
Yukarıdaki kodda:
- Koleksiyon,
Pizzas
pizzalar tablosundaki tüm satırları içerir. - Uzantı yöntemi EF
AsNoTracking
Core'a değişiklik izlemeyi devre dışı bırakmasını emreder. Bu işlem saltAsNoTracking
okunur olduğundan performansı iyileştirebilir. - Tüm pizzalar ile
ToList
geri döndürülür.
- Koleksiyon,
GetById
yöntemini aşağıdaki kod ile değiştirin:public Pizza? GetById(int id) { return _context.Pizzas .Include(p => p.Toppings) .Include(p => p.Sauce) .AsNoTracking() .SingleOrDefault(p => p.Id == id); }
Yukarıdaki kodda:
- Uzantı yöntemi,
Include
veSauce
gezinti özelliklerinin istekli yükleme kullanılarak sonuba dahil edileceklerini belirtmekToppings
için bir lambda ifadesi alır. Bu ifade olmadan EF Core bu özellikler için null döndürür. - yöntemi lambda
SingleOrDefault
ifadesiyle eşleşen bir pizza döndürür.- Eşleşen kayıt yoksa döndürülür
null
. - Birden çok kayıt eşleşirse, bir özel durum oluşturulur.
- Lambda ifadesi, özelliğin parametresine
Id
id
eşit olduğu kayıtları açıklar.
- Eşleşen kayıt yoksa döndürülür
- Uzantı yöntemi,
Create
yöntemini aşağıdaki kod ile değiştirin:public Pizza Create(Pizza newPizza) { _context.Pizzas.Add(newPizza); _context.SaveChanges(); return newPizza; }
Yukarıdaki kodda:
newPizza
geçerli bir nesne olduğu varsayılır. EF Core veri doğrulama yapmaz, bu nedenle herhangi bir doğrulamanın ASP.NET Core çalışma zamanı veya kullanıcı kodu tarafından işlenmesi gerekir.- yöntemi,
Add
varlığı EF Core nesne grafiğine eklernewPizza
. - yöntemi EF
SaveChanges
Core'a nesne değişikliklerinin veritabanında kalıcı olmasını bildirir.
UpdateSauce
yöntemini aşağıdaki kod ile değiştirin:public void UpdateSauce(int pizzaId, int sauceId) { var pizzaToUpdate = _context.Pizzas.Find(pizzaId); var sauceToUpdate = _context.Sauces.Find(sauceId); if (pizzaToUpdate is null || sauceToUpdate is null) { throw new InvalidOperationException("Pizza or sauce does not exist"); } pizzaToUpdate.Sauce = sauceToUpdate; _context.SaveChanges(); }
Yukarıdaki kodda:
- Var olan
Pizza
veSauce
nesnelere başvurular kullanılarakFind
oluşturulur.Find
, kayıtları birincil anahtarlarına göre sorgulamak için iyileştirilmiş bir yöntemdir.Find
veritabanını sorgulamadan önce yerel varlık grafını arar. Pizza.Sauce
özelliği nesnesineSauce
ayarlanır.Update
EF Core özelliğini üzerindePizza
ayarladığınızıSauce
algıladığından yöntem çağrısı gereksizdir.- yöntemi EF
SaveChanges
Core'a nesne değişikliklerinin veritabanında kalıcı olmasını bildirir.
- Var olan
AddTopping
yöntemini aşağıdaki kod ile değiştirin:public void AddTopping(int pizzaId, int toppingId) { var pizzaToUpdate = _context.Pizzas.Find(pizzaId); var toppingToAdd = _context.Toppings.Find(toppingId); if (pizzaToUpdate is null || toppingToAdd is null) { throw new InvalidOperationException("Pizza or topping does not exist"); } if(pizzaToUpdate.Toppings is null) { pizzaToUpdate.Toppings = new List<Topping>(); } pizzaToUpdate.Toppings.Add(toppingToAdd); _context.SaveChanges(); }
Yukarıdaki kodda:
- Var olan
Pizza
veTopping
nesnelere başvurular kullanılarakFind
oluşturulur. Topping
nesnesi yöntemiyle koleksiyonaPizza.Toppings
.Add
eklenir. Yoksa yeni bir koleksiyon oluşturulur.- yöntemi EF
SaveChanges
Core'a nesne değişikliklerinin veritabanında kalıcı olmasını bildirir.
- Var olan
DeleteById
yöntemini aşağıdaki kod ile değiştirin:public void DeleteById(int id) { var pizzaToDelete = _context.Pizzas.Find(id); if (pizzaToDelete is not null) { _context.Pizzas.Remove(pizzaToDelete); _context.SaveChanges(); } }
Yukarıdaki kodda:
Find
yöntemi birincil anahtara göre bir pizza alır (Id
bu durumda).- yöntemi EF
Remove
Core'un nesne grafında varlığı kaldırırpizzaToDelete
. - yöntemi EF
SaveChanges
Core'a nesne değişikliklerinin veritabanında kalıcı olmasını bildirir.
Tüm değişikliklerinizi kaydedin ve komutunu çalıştırın
dotnet build
. Oluşan hataları düzeltin.
Veritabanının tohumunu oluşturma
crud işlemlerini için PizzaService
kodladiniz, ancak veritabanında iyi veriler varsa okuma işlemini test etmek daha kolaydır. Başlangıçta veritabanının kaynağını belirlemek için uygulamayı değiştirmeye karar verirsiniz.
Uyarı
Bu veritabanı tohumlama kodu yarış koşullarını hesaba eklemediğinden, değişiklikleri azaltmadan dağıtılmış bir ortamda kullanırken dikkatli olun.
Veri klasörüne DbInitializer.cs adlı yeni bir dosya ekleyin.
Aşağıdaki kodu Data\DbInitializer.cs dosyasına ekleyin:
using ContosoPizza.Models; namespace ContosoPizza.Data { public static class DbInitializer { public static void Initialize(PizzaContext context) { if (context.Pizzas.Any() && context.Toppings.Any() && context.Sauces.Any()) { return; // DB has been seeded } var pepperoniTopping = new Topping { Name = "Pepperoni", Calories = 130 }; var sausageTopping = new Topping { Name = "Sausage", Calories = 100 }; var hamTopping = new Topping { Name = "Ham", Calories = 70 }; var chickenTopping = new Topping { Name = "Chicken", Calories = 50 }; var pineappleTopping = new Topping { Name = "Pineapple", Calories = 75 }; var tomatoSauce = new Sauce { Name = "Tomato", IsVegan = true }; var alfredoSauce = new Sauce { Name = "Alfredo", IsVegan = false }; var pizzas = new Pizza[] { new Pizza { Name = "Meat Lovers", Sauce = tomatoSauce, Toppings = new List<Topping> { pepperoniTopping, sausageTopping, hamTopping, chickenTopping } }, new Pizza { Name = "Hawaiian", Sauce = tomatoSauce, Toppings = new List<Topping> { pineappleTopping, hamTopping } }, new Pizza { Name="Alfredo Chicken", Sauce = alfredoSauce, Toppings = new List<Topping> { chickenTopping } } }; context.Pizzas.AddRange(pizzas); context.SaveChanges(); } } }
Yukarıdaki kodda:
DbInitializer
sınıfı veInitialize
yöntemi olarak tanımlanırstatic
.Initialize
birPizzaContext
nesneyi parametre olarak kabul eder.- Üç tablodan herhangi birinde kayıt yoksa,
Pizza
,Sauce
veTopping
nesneleri oluşturulur. Pizza
Nesneler (ve bunlarınSauce
veTopping
gezinti özellikleri) kullanılarakAddRange
nesne grafiğine eklenir.- Nesne grafı değişiklikleri kullanılarak
SaveChanges
veritabanına işlenir.
DbInitializer
sınıfı veritabanının tohumunu oluşturmaya hazırdır, ancak Program.cs dosyasından çağrılması gerekir. Aşağıdaki adımlar çağrısı DbInitializer.Initialize
için bir uzantı yöntemi IHost
oluşturur:
Veri klasörüne Extensions.cs adlı yeni bir dosya ekleyin.
Aşağıdaki kodu Data\Extensions.cs dosyasına ekleyin:
namespace ContosoPizza.Data; public static class Extensions { public static void CreateDbIfNotExists(this IHost host) { { using (var scope = host.Services.CreateScope()) { var services = scope.ServiceProvider; var context = services.GetRequiredService<PizzaContext>(); context.Database.EnsureCreated(); DbInitializer.Initialize(context); } } } }
Yukarıdaki kodda:
CreateDbIfNotExists
yöntemi uzantısıIHost
olarak tanımlanır.Hizmete bir
PizzaContext
başvuru oluşturulur.EnsureCreated , veritabanının mevcut olduğundan emin olur.
Önemli
Veritabanı yoksa yeni
EnsureCreated
bir veritabanı oluşturur. Yeni veritabanı geçişler için yapılandırılmamış, bu nedenle bu yöntemi dikkatli kullanın.DbIntializer.Initialize
yöntemi çağrılır.PizzaContext
Nesnesi parametre olarak geçirilir.
Son olarak, Program.cs dosyasında yeni uzantı yöntemini çağırmak için açıklamasını aşağıdaki kodla değiştirin
// Add the CreateDbIfNotExists method call
:app.CreateDbIfNotExists();
Bu kod, uygulama her çalıştığında daha önce tanımladığınız uzantı yöntemini çağırır.
Tüm değişikliklerinizi kaydedin ve komutunu çalıştırın
dotnet build
.
Temel CRUD işlemleri yapmak için ihtiyacınız olan tüm kodu yazdınız ve başlangıçta veritabanının tohumunu oluşturdunuz. Sonraki alıştırmada bu işlemleri uygulamada test edin.