Sdílet prostřednictvím


Kurz: Použití asynchronních a uložených procedur s EF v aplikaci ASP.NET MVC

V předchozích kurzech jste se naučili číst a aktualizovat data pomocí synchronního programovacího modelu. V tomto kurzu se dozvíte, jak implementovat asynchronní programovací model. Asynchronní kód může aplikaci pomoct lépe fungovat, protože lépe využívá prostředky serveru.

V tomto kurzu se také dozvíte, jak používat uložené procedury pro operace vložení, aktualizace a odstranění entity.

Nakonec znovu nasadíte aplikaci do Azure spolu se všemi změnami databáze, které jste implementovali od prvního nasazení.

Následující ilustrace znázorňují některé ze stránek, se kterými budete pracovat.

Stránka Oddělení

Vytvořit oddělení

V tomto kurzu jste:

  • Informace o asynchronním kódu
  • Vytvoření kontroleru oddělení
  • Použití uložených procedur
  • Nasazení do Azure

Požadavky

Proč používat asynchronní kód

Webový server má k dispozici omezený počet vláken a v situacích s vysokým zatížením se můžou používat všechna dostupná vlákna. Když k tomu dojde, nemůže server zpracovávat nové požadavky, dokud se vlákna neuvolní. U synchronního kódu může být mnoho vláken svázaných, zatímco ve skutečnosti neprovádí žádnou práci, protože čekají na dokončení vstupně-výstupních operací. Když proces čeká na dokončení vstupně-výstupních operací v asynchronním kódu, uvolní se jeho vlákno, aby ho server použil ke zpracování dalších požadavků. V důsledku toho asynchronní kód umožňuje efektivněji používat prostředky serveru a server může bez zpoždění zpracovávat více přenosů.

V dřívějších verzích rozhraní .NET bylo psaní a testování asynchronního kódu složité, náchylné k chybám a bylo obtížné ladit. V .NET 4.5 je psaní, testování a ladění asynchronního kódu mnohem jednodušší, že byste obecně měli psát asynchronní kód, pokud nemáte důvod ne. Asynchronní kód přináší malou režii, ale v situacích s nízkým provozem je výkonový zásah zanedbatelný, zatímco v situacích s vysokým provozem je potenciální zlepšení výkonu podstatné.

Další informace o asynchronním programování najdete v tématu Použití asynchronní podpory rozhraní .NET 4.5 k zabránění blokování volání.

Vytvoření kontroleru oddělení

Vytvořte kontroler oddělení stejným způsobem jako u předchozích kontrolerů, ale tentokrát zaškrtněte políčko Použít akce asynchronního kontroleru .

Následující zvýraznění ukazují, co bylo přidáno do synchronního kódu pro metodu Index , aby byla asynchronní:

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

Byly použity čtyři změny, které umožňují asynchronní spouštění dotazů na databázi Entity Framework:

  • Metoda je označena klíčovým slovem async , které kompilátoru říká, aby vygeneroval zpětná volání pro části těla metody a automaticky vytvořil vrácený Task<ActionResult> objekt.
  • Návratový typ se změnil z ActionResult na Task<ActionResult>. Typ Task<T> představuje probíhající práci s výsledkem typu T.
  • Klíčové await slovo se použilo pro volání webové služby. Když kompilátor uvidí toto klíčové slovo, na pozadí rozdělí metodu na dvě části. První část končí operací, která se spouští asynchronně. Druhá část je vložena do metody zpětného volání, která je volána po dokončení operace.
  • Asynchronní verze ToList rozšiřující metody byla volána.

Proč se departments.ToList příkaz změnil, ale ne příkaz?departments = db.Departments Důvodem je, že pouze příkazy, které způsobují odesílání dotazů nebo příkazů do databáze, jsou spouštěny asynchronně. Příkaz departments = db.Departments nastaví dotaz, ale dotaz se nespustí, dokud ToList není volána metoda. Proto je ToList pouze metoda spuštěna asynchronně.

Details V metodě aEditHttpGetmetodách a metodách a Delete je metoda ta, Find která způsobí odeslání dotazu do databáze, takže je to metoda, která se spouští asynchronně:

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);
}

CreateV metodách , HttpPost Edita DeleteConfirmed je SaveChanges to volání metody, které způsobuje spuštění příkazu, nikoli příkazy, jako db.Departments.Add(department) jsou, které způsobují pouze entity v paměti, aby byly změněny.

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

Otevřete Views\Department\Index.cshtml a nahraďte kód šablony následujícím kódem:

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

Tento kód změní název z indexu na Oddělení, přesune jméno správce doprava a poskytne úplné jméno správce.

V zobrazeníCh Vytvořit, Odstranit, Podrobnosti a Upravit změňte popis pro InstructorID pole na Správce stejným způsobem, jakým jste v zobrazeních kurzu změnili pole s názvem oddělení na Oddělení.

V zobrazení Vytvořit a Upravit použijte následující kód:

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

V zobrazení Odstranit a Podrobnosti použijte následující kód:

<dt>
    Administrator
</dt>

Spusťte aplikaci a klikněte na kartu Oddělení .

Všechno funguje stejně jako v ostatních řadičích, ale v tomto kontroleru se všechny dotazy SQL spouští asynchronně.

Při používání asynchronního programování v Entity Frameworku je potřeba mít na paměti několik věcí:

  • Asynchronní kód není bezpečný z více vláken. Jinými slovy, nepokoušejte se provádět více operací paralelně pomocí stejné instance kontextu.
  • Pokud chcete využívat výhody výkonu asynchronního kódu, ujistěte se, že všechny balíčky knihovny, které používáte (například pro stránkování), také použijte asynchronní, pokud volají metody Entity Framework, které způsobují odesílání dotazů do databáze.

Použití uložených procedur

Někteří vývojáři a dbaři dávají přednost používání uložených procedur pro přístup k databázi. V dřívějších verzích Entity Frameworku můžete načíst data pomocí uložené procedury spuštěním nezpracovaného dotazu SQL, ale nemůžete dát EF pokyn, aby pro operace aktualizace používal uložené procedury. V EF 6 je snadné nakonfigurovat Code First pro použití uložených procedur.

  1. V souboru DAL\SchoolContext.cs přidejte zvýrazněný kód 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();
    }
    

    Tento kód dává Entity Frameworku pokyn k použití uložených procedur pro operace Department vložení, aktualizace a odstranění entity.

  2. V části Konzola pro správu balíčků zadejte následující příkaz:

    add-migration DepartmentSP

    Otevřete soubor Migrations\<timestamp>_DepartmentSP.cs a zobrazte kód v Up metodě, která vytváří uložené procedury Insert, Update a 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. V části Konzola pro správu balíčků zadejte následující příkaz:

    update-database

  4. Spusťte aplikaci v režimu ladění, klikněte na kartu Oddělení a pak klikněte na Vytvořit novou.

  5. Zadejte data pro nové oddělení a klikněte na Vytvořit.

  6. V sadě Visual Studio se podívejte na protokoly v okně Výstup a zjistěte, že se k vložení nového řádku Oddělení použila uložená procedura.

    Oddělení Insert SP

Code First vytvoří výchozí názvy uložených procedur. Pokud používáte existující databázi, možná budete muset přizpůsobit názvy uložených procedur, aby bylo možné používat uložené procedury, které jsou v databázi už definované. Informace o tom, jak to provést, najdete v tématu Entity Framework Code First Insert/Update/Delete Stored Procedures.

Pokud chcete přizpůsobit, co vygenerované uložené procedury dělají, můžete upravit vygenerovaný Up kód pro metodu migrace, která vytvoří uloženou proceduru. Změny se tak projeví při každém spuštění migrace a použijí se na produkční databázi, když se migrace po nasazení automaticky spustí v produkčním prostředí.

Pokud chcete změnit existující uloženou proceduru vytvořenou při předchozí migraci, můžete pomocí příkazu Add-Migration vygenerovat prázdnou migraci a ručně napsat kód, který volá metodu AlterStoredProcedure .

Nasazení do Azure

Tato část vyžaduje, abyste dokončili volitelnou část Nasazení aplikace do Azure v kurzu Migrace a nasazení této série. Pokud došlo k chybám migrace, které jste vyřešili odstraněním databáze v místním projektu, přeskočte tuto část.

  1. V sadě Visual Studio klikněte pravým tlačítkem na projekt v Průzkumník řešení a v místní nabídce vyberte Publikovat.

  2. Klikněte na Publikovat.

    Visual Studio nasadí aplikaci do Azure a aplikace se otevře ve výchozím prohlížeči, který běží v Azure.

  3. Otestujte aplikaci a ověřte, že funguje.

    Při prvním spuštění stránky, která přistupuje k databázi, Entity Framework spustí všechny metody migrace Up potřebné k tomu, aby databáze byla aktuální s aktuálním datovým modelem. Teď můžete použít všechny webové stránky, které jste přidali od posledního nasazení, včetně stránek oddělení, které jste přidali v tomto kurzu.

Získání kódu

Stažení dokončeného projektu

Další materiály

Odkazy na další prostředky Entity Frameworku najdete v tématu ASP.NET Přístup k datům – doporučené zdroje.

Další kroky

V tomto kurzu jste:

  • Seznámení s asynchronním kódem
  • Vytvoření kontroleru oddělení
  • Použité uložené procedury
  • Nasazeno do Azure

V dalším článku se dozvíte, jak řešit konflikty, když více uživatelů aktualizuje stejnou entitu najednou.