Bagikan melalui


Tutorial: Menggunakan prosedur asinkron dan tersimpan dengan EF di aplikasi MVC ASP.NET

Dalam tutorial sebelumnya Anda mempelajari cara membaca dan memperbarui data menggunakan model pemrograman sinkron. Dalam tutorial ini Anda melihat cara mengimplementasikan model pemrograman asinkron. Kode asinkron dapat membantu aplikasi berkinerja lebih baik karena membuat penggunaan sumber daya server lebih baik.

Dalam tutorial ini Anda juga melihat cara menggunakan prosedur tersimpan untuk menyisipkan, memperbarui, dan menghapus operasi pada entitas.

Terakhir, Anda menyebarkan ulang aplikasi ke Azure, bersama dengan semua perubahan database yang telah Anda terapkan sejak pertama kali Anda menyebarkan.

Ilustrasi berikut ini memperlihatkan beberapa halaman yang akan Anda kerjakan.

Halaman Departemen

Buat Departemen

Di tutorial ini, Anda akan:

  • Pelajari tentang kode asinkron
  • Membuat pengontrol Departemen
  • Menggunakan prosedur tersimpan
  • Sebarkan ke Azure

Prasyarat

Mengapa menggunakan kode asinkron

Server web memiliki jumlah utas terbatas yang tersedia, dan dalam situasi beban tinggi semua utas yang tersedia mungkin digunakan. Ketika itu terjadi, server tidak dapat memproses permintaan baru sampai utas dikosongkan. Dengan kode sinkron, banyak utas mungkin diikat sementara mereka tidak benar-benar melakukan pekerjaan apa pun karena mereka menunggu I/O selesai. Dengan kode asinkron, ketika proses menunggu I/O selesai, utasnya dibebaskan untuk digunakan server untuk memproses permintaan lain. Akibatnya, kode asinkron memungkinkan sumber daya server digunakan lebih efisien, dan server diaktifkan untuk menangani lebih banyak lalu lintas tanpa penundaan.

Dalam versi .NET sebelumnya, menulis dan menguji kode asinkron rumit, rawan kesalahan, dan sulit di-debug. Dalam .NET 4.5, menulis, menguji, dan men-debug kode asinkron jauh lebih mudah sehingga Anda umumnya harus menulis kode asinkron kecuali Anda memiliki alasan untuk tidak. Kode asinkron memang memperkenalkan sejumlah kecil overhead, tetapi untuk situasi lalu lintas rendah, hit performa dapat diabaikan, sementara untuk situasi lalu lintas yang tinggi, potensi peningkatan performa sangat besar.

Untuk informasi selengkapnya tentang pemrograman asinkron, lihat Menggunakan dukungan asinkron .NET 4.5 untuk menghindari pemblokiran panggilan.

Membuat pengontrol Departemen

Buat pengontrol Departemen dengan cara yang sama seperti Anda melakukan pengontrol sebelumnya, kecuali kali ini pilih kotak centang Gunakan tindakan pengontrol asinkron.

Sorotan berikut menunjukkan apa yang ditambahkan ke kode sinkron untuk Index metode untuk membuatnya asinkron:

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

Empat perubahan diterapkan untuk mengaktifkan kueri database Kerangka Kerja Entitas untuk dijalankan secara asinkron:

  • Metode ini ditandai dengan async kata kunci, yang memberi tahu pengkompilasi untuk menghasilkan panggilan balik untuk bagian isi metode dan untuk secara otomatis membuat Task<ActionResult> objek yang dikembalikan.
  • Jenis pengembalian diubah dari ActionResult ke Task<ActionResult>. Jenis mewakili Task<T> pekerjaan yang sedang berlangsung dengan hasil dari jenis T.
  • Kata await kunci diterapkan ke panggilan layanan web. Ketika pengkompilasi melihat kata kunci ini, di balik layar, ia membagi metode menjadi dua bagian. Bagian pertama berakhir dengan operasi yang dimulai secara asinkron. Bagian kedua dimasukkan ke dalam metode panggilan balik yang dipanggil ketika operasi selesai.
  • Versi asinkron dari ToList metode ekstensi dipanggil.

Mengapa pernyataan dimodifikasi departments.ToList tetapi bukan pernyataannya departments = db.Departments ? Alasannya adalah bahwa hanya pernyataan yang menyebabkan kueri atau perintah dikirim ke database yang dijalankan secara asinkron. Pernyataan departments = db.Departments menyiapkan kueri tetapi kueri tidak dijalankan sampai metode dipanggil ToList . Oleh karena itu, hanya metode yang ToList dijalankan secara asinkron.

Details Dalam metode dan HttpGet Edit metode dan Delete , Find metode adalah metode yang menyebabkan kueri dikirim ke database, jadi itulah metode yang dieksekusi secara asinkron:

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

CreateDalam metode , HttpPost Edit, dan DeleteConfirmed , itu adalah SaveChanges panggilan metode yang menyebabkan perintah dijalankan, bukan pernyataan seperti db.Departments.Add(department) yang hanya menyebabkan entitas dalam memori dimodifikasi.

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

Buka Views\Department\Index.cshtml, dan ganti kode templat dengan kode berikut:

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

Kode ini mengubah judul dari Indeks ke Departemen, memindahkan nama Administrator ke kanan, dan memberikan nama lengkap administrator.

Di tampilan Buat, Hapus, Detail, dan Edit, ubah keterangan untuk InstructorID bidang menjadi "Administrator" dengan cara yang sama seperti Anda mengubah bidang nama departemen menjadi "Departemen" dalam tampilan Kursus.

Di tampilan Buat dan Edit gunakan kode berikut:

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

Dalam tampilan Hapus dan Detail gunakan kode berikut:

<dt>
    Administrator
</dt>

Jalankan aplikasi, dan klik tab Departemen .

Semuanya berfungsi sama seperti di pengontrol lain, tetapi dalam pengontrol ini semua kueri SQL dijalankan secara asinkron.

Beberapa hal yang perlu diperhatikan saat Anda menggunakan pemrograman asinkron dengan Kerangka Kerja Entitas:

  • Kode asinkron tidak aman utas. Dengan kata lain, jangan mencoba melakukan beberapa operasi secara paralel menggunakan instans konteks yang sama.
  • Jika Anda ingin memanfaatkan manfaat performa kode asinkron, pastikan bahwa paket pustaka apa pun yang Anda gunakan (seperti untuk penomoran halaman), juga gunakan asinkron jika mereka memanggil metode Kerangka Kerja Entitas apa pun yang menyebabkan kueri dikirim ke database.

Menggunakan prosedur tersimpan

Beberapa pengembang dan DBA lebih suka menggunakan prosedur tersimpan untuk akses database. Dalam versi Kerangka Kerja Entitas yang lebih lama, Anda dapat mengambil data menggunakan prosedur tersimpan dengan menjalankan kueri SQL mentah, tetapi Anda tidak dapat menginstruksikan EF untuk menggunakan prosedur tersimpan untuk operasi pembaruan. Di EF 6 mudah untuk mengonfigurasi Code First untuk menggunakan prosedur tersimpan.

  1. Di DAL\SchoolContext.cs, tambahkan kode yang disorot ke OnModelCreating metode .

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

    Kode ini menginstruksikan Entity Framework untuk menggunakan prosedur tersimpan untuk operasi sisipkan, perbarui, dan hapus pada Department entitas.

  2. Di Konsol Kelola Paket, masukkan perintah berikut:

    add-migration DepartmentSP

    Buka Migrations\<timestamp_DepartmentSP.cs untuk melihat kode dalam Up metode yang membuat prosedur Sisipkan, Perbarui, dan Hapus tersimpan>:

    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. Di Konsol Kelola Paket, masukkan perintah berikut:

    update-database

  4. Jalankan aplikasi dalam mode debug, klik tab Departemen , lalu klik Buat Baru.

  5. Masukkan data untuk departemen baru, lalu klik Buat.

  6. Di Visual Studio, lihat log di jendela Output untuk melihat bahwa prosedur tersimpan digunakan untuk menyisipkan baris Departemen baru.

    Departemen Sisipkan SP

Code First membuat nama prosedur tersimpan default. Jika Anda menggunakan database yang sudah ada, Anda mungkin perlu menyesuaikan nama prosedur tersimpan untuk menggunakan prosedur tersimpan yang sudah ditentukan dalam database. Untuk informasi tentang cara melakukannya, lihat Kode Kerangka Kerja Entitas Terlebih Dahulu Sisipkan/Perbarui/Hapus Prosedur Tersimpan.

Jika Anda ingin menyesuaikan apa yang dilakukan prosedur tersimpan yang dihasilkan, Anda dapat mengedit kode perancah untuk metode migrasi Up yang membuat prosedur tersimpan. Dengan begitu perubahan Anda tercermin setiap kali migrasi dijalankan dan akan diterapkan ke database produksi Anda saat migrasi berjalan secara otomatis dalam produksi setelah penyebaran.

Jika Anda ingin mengubah prosedur tersimpan yang sudah ada yang dibuat dalam migrasi sebelumnya, Anda dapat menggunakan perintah Add-Migration untuk menghasilkan migrasi kosong, lalu menulis kode secara manual yang memanggil metode AlterStoredProcedure .

Sebarkan ke Azure

Bagian ini mengharuskan Anda untuk menyelesaikan bagian Menyebarkan aplikasi ke Azure opsional dalam tutorial Migrasi dan Penyebaran seri ini. Jika Anda mengalami kesalahan migrasi yang Anda atasi dengan menghapus database di proyek lokal Anda, lewati bagian ini.

  1. Di Visual Studio, klik kanan proyek di Penjelajah Solusi dan pilih Terbitkan dari menu konteks.

  2. Klik Publikasikan.

    Visual Studio menyebarkan aplikasi ke Azure, dan aplikasi terbuka di browser default Anda, yang berjalan di Azure.

  3. Uji aplikasi untuk memverifikasi bahwa aplikasi berfungsi.

    Pertama kali Anda menjalankan halaman yang mengakses database, Kerangka Kerja Entitas menjalankan semua metode migrasi yang Up diperlukan untuk memperbarui database dengan model data saat ini. Anda sekarang dapat menggunakan semua halaman web yang Anda tambahkan sejak terakhir kali Anda menyebarkan, termasuk halaman Departemen yang Anda tambahkan dalam tutorial ini.

Mendapatkan kode

Unduh Proyek yang Selesai

Sumber Daya Tambahan:

Tautan ke sumber daya Kerangka Kerja Entitas lainnya dapat ditemukan di Akses Data ASP.NET - Sumber Daya yang Direkomendasikan.

Langkah berikutnya

Di tutorial ini, Anda akan:

  • Dipelajari tentang kode asinkron
  • Membuat pengontrol Departemen
  • Prosedur tersimpan yang digunakan
  • Disebarkan ke Azure

Lanjutkan ke artikel berikutnya untuk mempelajari cara menangani konflik saat beberapa pengguna memperbarui entitas yang sama secara bersamaan.