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

  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 sınıf düzeyi bir alan ekleyin.
    4. Bir parametreyi kabul PizzaContext etmek için oluşturucu yöntemi imzasını değiştirin.
    5. 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 bir PizzaContext eklenir.

  2. 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 ToListdö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);
    }
    

    Önceki kodda:

    • Include Uzantı yöntemi, ve Sauce gezinti özelliklerinin hevesle 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 döndürür null .
    • 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.
  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;
    }
    

    Ö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 ekler newPizza .
    • yöntemi EF SaveChanges Core'a nesne değişikliklerinin veritabanında kalıcı olmasını bildirir.
  5. 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 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.
  6. 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 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ığı 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.
  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();
        }        
    }
    

    Önceki kodda:

    • Find yöntemi birincil anahtara göre bir pizza alır (Idbu 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.
  8. 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 PizzaServicekodladı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.

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

  2. 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 hem Initialize de yöntem olarak statictanımlanır.
    • 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 çağrılması gerekir. Aşağıdaki adımlar, çağrısı DbInitializer.Initializeiçin IHost bir uzantı yöntemi oluşturur:

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

  2. 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ı 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ılmadığından 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 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.

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

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?