Alıştırma - Verilerle etkileşim kurma
Önceki alıştırmada varlık sınıfları ve veritabanı bağlamı oluşturdunuz. Ardından EF Core geçişlerini kullanarak veritabanı şemasını oluşturmuştsunuz.
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 kodlayın
Uygulamayı tamamlamak PizzaService
için Services\PizzaService.cs bölümünde 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
sınıf düzeyi bir alan ekleyin. - Bir parametreyi kabul
PizzaContext
etmek için oluşturucu yöntemi imzasını değiştirin. - Parametresini alana atamak için oluşturucu yöntemi 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 kaydedilmişPizzaContext
Program.cs 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(); }
Önceki kodda:
- Koleksiyon,
Pizzas
pizzalar tablosundaki tüm satırları içerir. AsNoTracking
Uzantı yöntemi EF Core'a değişiklik izlemeyi devre dışı bırakmasını sağlar. Bu işlem salt okunur olduğundan performansıAsNoTracking
iyileştirebilir.- Tüm pizzalar ile
ToList
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); }
Önceki kodda:
Include
Uzantı yöntemi, veSauce
gezinti özelliklerinin hevesle yükleme kullanılarak sonuba dahil edileceklerini belirtmekToppings
için bir lambda ifadesi alır. Bu ifade olmadan EF Core bu özellikler için döndürürnull
.- yöntemi,
SingleOrDefault
lambda 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
Create
yöntemini aşağıdaki kod ile değiştirin:public Pizza Create(Pizza newPizza) { _context.Pizzas.Add(newPizza); _context.SaveChanges(); return newPizza; }
Önceki kodda:
newPizza
geçerli bir nesne olduğu varsayılır. EF Core veri doğrulama yapmaz, bu nedenle ASP.NET Core çalışma zamanı veya kullanıcı kodu herhangi bir doğrulamayı işlemelidir.- 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.
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(); }
Önceki 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
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(); }
Önceki 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ığı için 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
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(); } }
Önceki kodda:
Find
yöntemi birincil anahtara göre bir pizza alır (Id
bu durumda).Remove
yöntemi EF Core'un nesne grafiğindeki 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 çalıştırın
dotnet build
. Oluşan hataları düzeltin.
Veritabanının tohumunu oluşturma
crud işlemlerini için PizzaService
kodladıysanız ancak veritabanı iyi veriler içeriyorsa Okuma işlemini test etmek daha kolaydır. Başlangıçta veritabanının tohumunu oluşturmak 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.
Data\DbInitializer.cs'a aşağıdaki kodu 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(); } } }
Önceki kodda:
- Hem
DbInitializer
sınıf hemInitialize
de yöntem olarakstatic
tanımlanır. 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.
- Hem
DbInitializer
sınıfı veritabanının tohumunu oluşturmaya hazırdır, ancak Program.cs çağrılması gerekir. Aşağıdaki adımlar, çağrısı DbInitializer.Initialize
için IHost
bir uzantı yöntemi oluşturur:
Veri klasörüne Extensions.cs adlı yeni bir dosya ekleyin.
Data\Extensions.cs'a aşağıdaki kodu 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); } } } }
Önceki 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ılmadığından bu yöntemi dikkatli kullanın.DbIntializer.Initialize
yöntemi çağrılır.PizzaContext
Nesnesi parametre olarak geçirilir.
Son olarak, Program.cs yeni uzantı yöntemini çağırmak için açıklamayı 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 ç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şturacaksınız. Sonraki alıştırmada bu işlemleri uygulamada test edin.