Alıştırma - Verilerle etkileşim kurma

Tamamlandı

Ö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:

  1. Örnekte gösterildiği gibi aşağıdaki değişiklikleri yapın:

    1. Yönerge using ContosoPizza.Data; ekleyin.
    2. Yönerge using Microsoft.EntityFrameworkCore; ekleyin.
    3. Oluşturucudan önce için PizzaContext bir sınıf düzeyi alanı ekleyin.
    4. Oluşturucu yöntemi imzasını parametre PizzaContext kabul etmek için değiştirin.
    5. 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ına PizzaContext eklediğiniz yöntem çağrısı. PizzaService Örnek oluşturulduğunda oluşturucuya bir PizzaContext eklenir.

  2. 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 salt AsNoTracking okunur olduğundan performansı iyileştirebilir.
    • Tüm pizzalar ile ToListgeri döndürülür.
  3. 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 ve Sauce gezinti özelliklerinin istekli yükleme kullanılarak sonuba dahil edileceklerini belirtmek Toppings 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 Idid eşit olduğu kayıtları açıklar.
  4. 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 ekler newPizza .
    • yöntemi EF SaveChanges Core'a nesne değişikliklerinin veritabanında kalıcı olmasını bildirir.
  5. 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 ve Sauce nesnelere başvurular kullanılarak Findoluş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 nesnesine Sauce ayarlanır.
    • Update EF Core özelliğini üzerinde Pizzaayarladığı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.
  6. 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 ve Topping nesnelere başvurular kullanılarak Findoluşturulur.
    • Topping nesnesi yöntemiyle koleksiyona Pizza.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.
  7. 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 (Idbu durumda).
    • yöntemi EF Remove Core'un nesne grafında varlığı kaldırır pizzaToDelete .
    • yöntemi EF SaveChanges Core'a nesne değişikliklerinin veritabanında kalıcı olmasını bildirir.
  8. 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 PizzaServicekodladiniz, 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.

  1. Veri klasörüne DbInitializer.cs adlı yeni bir dosya ekleyin.

  2. 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ı ve Initialize yöntemi olarak tanımlanırstatic.
    • Initialize bir PizzaContext nesneyi parametre olarak kabul eder.
    • Üç tablodan herhangi birinde kayıt yoksa, Pizza, Sauceve Topping nesneleri oluşturulur.
    • Pizza Nesneler (ve bunların Sauce ve Topping gezinti özellikleri) kullanılarak AddRangenesne grafiğine eklenir.
    • Nesne grafı değişiklikleri kullanılarak SaveChangesveritabanı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.Initializeiçin bir uzantı yöntemi IHost oluşturur:

  1. Veri klasörüne Extensions.cs adlı yeni bir dosya ekleyin.

  2. 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ı IHostolarak 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.

  3. 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.

  4. 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.

Bilginizi ölçün

1.

Bir salt okunur sorgu yazmak istediğinizi varsayalım. Nesne grafı değişikliğini izlemenin gereksiz olduğu EF Core’a nasıl gösterilir?