Samouczek: używanie procedur asynchronicznych i składowanych z platformą EF w aplikacji MVC ASP.NET

W poprzednich samouczkach przedstawiono sposób odczytywania i aktualizowania danych przy użyciu modelu programowania synchronicznego. W tym samouczku pokazano, jak zaimplementować model programowania asynchronicznego. Kod asynchroniczny może pomóc aplikacji w lepszym korzystaniu z zasobów serwera.

W tym samouczku zobaczysz również, jak używać procedur składowanych do operacji wstawiania, aktualizowania i usuwania w jednostce.

Na koniec ponownie wdrożysz aplikację na platformie Azure wraz ze wszystkimi zmianami bazy danych, które zostały wdrożone od czasu pierwszego wdrożenia.

Na poniższych ilustracjach przedstawiono niektóre strony, z którymi będziesz pracować.

Strona Działy

Tworzenie działu

W tym samouczku zostały wykonane następujące czynności:

  • Dowiedz się więcej o kodzie asynchronicznym
  • Tworzenie kontrolera działu
  • Korzystanie z procedur składowanych
  • Wdróż na platformie Azure

Wymagania wstępne

Dlaczego warto używać kodu asynchronicznego

Serwer internetowy ma dostępną ograniczoną liczbę wątków, a w sytuacjach dużego obciążenia wszystkie dostępne wątki mogą być używane. W takim przypadku serwer nie może przetworzyć nowych żądań, dopóki wątki nie zostaną zwolnione. W przypadku kodu synchronicznego wiele wątków może być powiązanych, gdy w rzeczywistości nie wykonują żadnej pracy, ponieważ oczekują na ukończenie operacji we/wy. W przypadku kodu asynchronicznego, gdy proces oczekuje na ukończenie operacji we/wy, jego wątek zostanie zwolniony, aby serwer był używany do przetwarzania innych żądań. W rezultacie kod asynchroniczny umożliwia wydajniejsze korzystanie z zasobów serwera, a serwer jest włączony do obsługi większej liczby ruchu bez opóźnień.

We wcześniejszych wersjach platformy .NET pisanie i testowanie kodu asynchronicznego było złożone, podatne na błędy i trudne do debugowania. W programie .NET 4.5 pisanie, testowanie i debugowanie kodu asynchronicznego jest o wiele łatwiejsze, ponieważ zwykle należy napisać kod asynchroniczny, chyba że masz powód, aby nie. Kod asynchroniczny wprowadza niewielką ilość narzutów, ale w przypadku sytuacji niskiego ruchu trafienie wydajności jest niewielkie, podczas gdy w przypadku sytuacji o dużym natężeniu ruchu potencjalna poprawa wydajności jest znacząca.

Aby uzyskać więcej informacji na temat programowania asynchronicznego, zobacz Używanie asynchronicznej obsługi asynchronicznej platformy .NET 4.5 w celu uniknięcia blokowania wywołań.

Tworzenie kontrolera działu

Utwórz kontroler działu w taki sam sposób, w jaki wykonaliśmy wcześniejsze kontrolery, z wyjątkiem tego czasu zaznacz pole wyboru Użyj akcji kontrolera asynchronicznego .

Poniższe wyróżnienia pokazują, co zostało dodane do synchronicznego kodu Index dla metody, aby było asynchroniczne:

public async Task<ActionResult> Index()
{
    var departments = db.Departments.Include(d => d.Administrator);
    return View(await departments.ToListAsync());
}

Zastosowano cztery zmiany, aby umożliwić wykonywanie asynchronicznego zapytania bazy danych platformy Entity Framework:

  • Metoda jest oznaczona async słowem kluczowym, które nakazuje kompilatorowi generowanie wywołań zwrotnych dla części treści metody i automatyczne tworzenie Task<ActionResult> zwracanego obiektu.
  • Typ zwracany został zmieniony z ActionResult na Task<ActionResult>. Typ Task<T> reprezentuje bieżącą pracę z wynikiem typu T.
  • Słowo await kluczowe zostało zastosowane do wywołania usługi internetowej. Gdy kompilator widzi to słowo kluczowe, za kulisami dzieli metodę na dwie części. Pierwsza część kończy się operacją uruchomioną asynchronicznie. Druga część jest umieszczana w metodzie wywołania zwrotnego wywoływanej po zakończeniu operacji.
  • Wywołano asynchroniczną wersję ToList metody rozszerzenia.

Dlaczego instrukcja została departments.ToList zmodyfikowana, ale nie instrukcja departments = db.Departments ? Przyczyną jest to, że tylko instrukcje, które powodują wysyłanie zapytań lub poleceń do bazy danych, są wykonywane asynchronicznie. Instrukcja departments = db.Departments konfiguruje zapytanie, ale zapytanie nie jest wykonywane, dopóki ToList metoda nie zostanie wywołana. W związku z ToList tym tylko metoda jest wykonywana asynchronicznie.

Details W metodzie i metodach i DeleteHttpGetEdit metoda jest metodą, Find która powoduje wysłanie zapytania do bazy danych, więc jest to metoda wykonywana asynchronicznie:

public async Task<ActionResult> Details(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Department department = await db.Departments.FindAsync(id);
    if (department == null)
    {
        return HttpNotFound();
    }
    return View(department);
}

W metodach Create, HttpPost Editi DeleteConfirmed jest SaveChanges to wywołanie metody, które powoduje wykonanie polecenia, a nie instrukcje, takie jak db.Departments.Add(department) , które powodują modyfikację tylko jednostek w pamięci.

public async Task<ActionResult> Create(Department department)
{
    if (ModelState.IsValid)
    {
        db.Departments.Add(department);
    await db.SaveChangesAsync();
        return RedirectToAction("Index");
    }

Otwórz plik Views\Department\Index.cshtml i zastąp kod szablonu następującym kodem:

@model IEnumerable<ContosoUniversity.Models.Department>
@{
    ViewBag.Title = "Departments";
}
<h2>Departments</h2>
<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Name)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Budget)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.StartDate)
        </th>
    <th>
            Administrator
        </th>
        <th></th>
    </tr>
@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Name)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Budget)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.StartDate)
        </td>
    <td>
            @Html.DisplayFor(modelItem => item.Administrator.FullName)
            </td>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id=item.DepartmentID }) |
            @Html.ActionLink("Details", "Details", new { id=item.DepartmentID }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.DepartmentID })
        </td>
    </tr>
}
</table>

Ten kod zmienia tytuł z Indeks na Działy, przenosi nazwę administratora po prawej stronie i udostępnia pełną nazwę administratora.

W widoku Tworzenie, Usuwanie, Szczegóły i Edytowanie zmień podpis pola InstructorID na "Administrator" w taki sam sposób, jak zmieniono pole nazwy działu na "Dział" w widokach kursu.

W obszarze Tworzenie i edytowanie widoków użyj następującego kodu:

<label class="control-label col-md-2" for="InstructorID">Administrator</label>

W widokach Usuń i Szczegóły użyj następującego kodu:

<dt>
    Administrator
</dt>

Uruchom aplikację i kliknij kartę Działy .

Wszystko działa tak samo jak w innych kontrolerach, ale w tym kontrolerze wszystkie zapytania SQL są wykonywane asynchronicznie.

Niektóre kwestie, które należy wziąć pod uwagę podczas korzystania z programowania asynchronicznego w programie Entity Framework:

  • Kod asynchroniczny nie jest bezpieczny wątkiem. Innymi słowy, nie próbuj wykonywać wielu operacji równolegle przy użyciu tego samego wystąpienia kontekstu.
  • Jeśli chcesz skorzystać z zalet wydajności kodu asynchronicznego, upewnij się, że wszystkie używane pakiety bibliotek (na przykład do stronicowania), należy również użyć asynchronicznego, jeśli wywołują dowolne metody programu Entity Framework, które powodują wysyłanie zapytań do bazy danych.

Korzystanie z procedur składowanych

Niektórzy deweloperzy i administratorzy baz danych wolą używać procedur składowanych na potrzeby dostępu do bazy danych. We wcześniejszych wersjach programu Entity Framework można pobrać dane przy użyciu procedury składowanej, wykonując nieprzetworzone zapytanie SQL, ale nie można poinstruować ef o użyciu procedur składowanych na potrzeby operacji aktualizacji. W programie EF 6 można łatwo skonfigurować funkcję Code First do korzystania z procedur składowanych.

  1. W pliku DAL\SchoolContext.cs dodaj wyróżniony kod do OnModelCreating metody .

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        modelBuilder.Entity<Course>()
            .HasMany(c => c.Instructors).WithMany(i => i.Courses)
            .Map(t => t.MapLeftKey("CourseID")
                .MapRightKey("InstructorID")
                .ToTable("CourseInstructor"));
        modelBuilder.Entity<Department>().MapToStoredProcedures();
    }
    

    Ten kod instruuje program Entity Framework, aby używał procedur składowanych do operacji wstawiania, aktualizowania i usuwania w jednostce Department .

  2. W obszarze Konsola zarządzania pakietami wprowadź następujące polecenie:

    add-migration DepartmentSP

    Otwórz plik Migrations\<timestamp>_DepartmentSP.cs , aby wyświetlić kod w Up metodzie, która tworzy procedury składowane Insert, Update i Delete:

    public override void Up()
    {
        CreateStoredProcedure(
            "dbo.Department_Insert",
            p => new
                {
                    Name = p.String(maxLength: 50),
                    Budget = p.Decimal(precision: 19, scale: 4, storeType: "money"),
                    StartDate = p.DateTime(),
                    InstructorID = p.Int(),
                },
            body:
                @"INSERT [dbo].[Department]([Name], [Budget], [StartDate], [InstructorID])
                  VALUES (@Name, @Budget, @StartDate, @InstructorID)
                  
                  DECLARE @DepartmentID int
                  SELECT @DepartmentID = [DepartmentID]
                  FROM [dbo].[Department]
                  WHERE @@ROWCOUNT > 0 AND [DepartmentID] = scope_identity()
                  
                  SELECT t0.[DepartmentID]
                  FROM [dbo].[Department] AS t0
                  WHERE @@ROWCOUNT > 0 AND t0.[DepartmentID] = @DepartmentID"
        );
        
        CreateStoredProcedure(
            "dbo.Department_Update",
            p => new
                {
                    DepartmentID = p.Int(),
                    Name = p.String(maxLength: 50),
                    Budget = p.Decimal(precision: 19, scale: 4, storeType: "money"),
                    StartDate = p.DateTime(),
                    InstructorID = p.Int(),
                },
            body:
                @"UPDATE [dbo].[Department]
                  SET [Name] = @Name, [Budget] = @Budget, [StartDate] = @StartDate, [InstructorID] = @InstructorID
                  WHERE ([DepartmentID] = @DepartmentID)"
        );
        
        CreateStoredProcedure(
            "dbo.Department_Delete",
            p => new
                {
                    DepartmentID = p.Int(),
                },
            body:
                @"DELETE [dbo].[Department]
                  WHERE ([DepartmentID] = @DepartmentID)"
        );    
    }
    
  3. W obszarze Konsola zarządzania pakietami wprowadź następujące polecenie:

    update-database

  4. Uruchom aplikację w trybie debugowania, kliknij kartę Działy , a następnie kliknij pozycję Utwórz nową.

  5. Wprowadź dane dla nowego działu, a następnie kliknij przycisk Utwórz.

  6. W programie Visual Studio przyjrzyj się dziennikom w oknie Dane wyjściowe , aby zobaczyć, że procedura składowana została użyta do wstawienia nowego wiersza Dział.

    Wstaw sp działu

Code First tworzy domyślne nazwy procedur składowanej. Jeśli używasz istniejącej bazy danych, może być konieczne dostosowanie nazw procedur składowanych w celu użycia procedur składowanych zdefiniowanych już w bazie danych. Aby uzyskać informacje o tym, jak to zrobić, zobacz Entity Framework Code First Insert/Update/Delete Stored Procedures (Procedury składowane w programie Entity Framework Code First Insert/Update/Delete).

Jeśli chcesz dostosować wygenerowane procedury składowane, możesz edytować kod szkieletowy dla metody migracji Up , która tworzy procedurę składowaną. Dzięki temu zmiany są odzwierciedlane za każdym razem, gdy migracja zostanie uruchomiona i zostanie zastosowana do produkcyjnej bazy danych, gdy migracje są uruchamiane automatycznie w środowisku produkcyjnym po wdrożeniu.

Jeśli chcesz zmienić istniejącą procedurę składowaną utworzoną w poprzedniej migracji, możesz użyć polecenia Add-Migration, aby wygenerować pustą migrację, a następnie ręcznie napisać kod, który wywołuje metodę AlterStoredProcedure .

Wdróż na platformie Azure

Ta sekcja wymaga ukończenia opcjonalnej sekcji Wdrażanie aplikacji na platformie Azure w samouczku Migracje i wdrażanie tej serii. Jeśli wystąpiły błędy migracji rozwiązane przez usunięcie bazy danych w projekcie lokalnym, pomiń tę sekcję.

  1. W programie Visual Studio kliknij prawym przyciskiem myszy projekt w Eksplorator rozwiązań i wybierz polecenie Publikuj z menu kontekstowego.

  2. Kliknij przycisk Opublikuj.

    Program Visual Studio wdraża aplikację na platformie Azure, a aplikacja zostanie otwarta w domyślnej przeglądarce uruchomionej na platformie Azure.

  3. Przetestuj aplikację, aby sprawdzić, czy działa.

    Po pierwszym uruchomieniu strony, która uzyskuje dostęp do bazy danych, program Entity Framework uruchamia wszystkie metody migracji Up wymagane do zapewnienia aktualności bazy danych z bieżącym modelem danych. Teraz możesz używać wszystkich dodanych stron internetowych od czasu ostatniego wdrożenia, w tym stron działu dodanych w tym samouczku.

Uzyskiwanie kodu

Pobieranie ukończonego projektu

Dodatkowe zasoby

Linki do innych zasobów platformy Entity Framework można znaleźć w ASP.NET Dostęp do danych — zalecane zasoby.

Następne kroki

W tym samouczku zostały wykonane następujące czynności:

  • Informacje o kodzie asynchronicznym
  • Tworzenie kontrolera działu
  • Używane procedury składowane
  • Wdrożone na platformie Azure

Przejdź do następnego artykułu, aby dowiedzieć się, jak obsługiwać konflikty, gdy wielu użytkowników aktualizuje tę samą jednostkę w tym samym czasie.