Öğretici: CRUD İşlevselliği Uygulama - ile MVC ASP.NET EF Core

Önceki öğreticide Entity Framework ve SQL Server LocalDB kullanarak verileri depolayan ve görüntüleyen bir MVC uygulaması oluşturdunuz. Bu öğreticide, MVC iskelesinin denetleyicilerde ve görünümlerde sizin için otomatik olarak oluşturduğu CRUD (oluşturma, okuma, güncelleştirme, silme) kodunu gözden geçirecek ve özelleştireceksiniz.

Dekont

Denetleyicinizle veri erişim katmanı arasında bir soyutlama katmanı oluşturmak için depo düzenini uygulamak yaygın bir uygulamadır. Bu öğreticileri basit tutmak ve Entity Framework'ün kendisini kullanmayı öğretmeye odaklanmak için depoları kullanmaz. EF ile depolar hakkında bilgi için bu serideki son öğreticiye bakın.

Bu öğreticide şunları yaptınız:

  • Ayrıntılar sayfasını özelleştirme
  • Oluştur sayfasını güncelleştirme
  • Düzenle sayfasını güncelleştirme
  • Sil sayfasını güncelleştirme
  • Veritabanı bağlantılarını kapatma

Ön koşullar

Ayrıntılar sayfasını özelleştirme

Öğrenci Dizini sayfasının iskelesi oluşturulmuş kodu özelliğin dışında Enrollments bıraktı, çünkü bu özellik bir koleksiyon barındırıyor. Ayrıntılar sayfasında, koleksiyonun içeriğini bir HTML tablosunda görüntülersiniz.

içindeControllers/StudentsController.cs, Ayrıntılar görünümünün eylem yöntemi tek Student bir varlığı almak için yöntemini kullanırFirstOrDefaultAsync. çağıran Includekodu ekleyin. ThenIncludeAsNoTracking ve yöntemleri, aşağıdaki vurgulanmış kodda gösterildiği gibi.

public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var student = await _context.Students
        .Include(s => s.Enrollments)
            .ThenInclude(e => e.Course)
        .AsNoTracking()
        .FirstOrDefaultAsync(m => m.ID == id);

    if (student == null)
    {
        return NotFound();
    }

    return View(student);
}

Include ve ThenInclude yöntemleri, bağlamın gezinti özelliğini yüklemesine Student.Enrollments ve her kayıtta gezinti özelliğinin Enrollment.Course içine neden olur. İlgili verileri okuma öğreticisinde bu yöntemler hakkında daha fazla bilgi edineceksiniz.

yöntemi, AsNoTracking döndürülen varlıkların geçerli bağlamın ömrü boyunca güncelleştirilmeyeceği senaryolarda performansı artırır. Bu öğreticinin sonunda hakkında AsNoTracking daha fazla bilgi edineceksiniz.

Veri yönlendirme

yöntemine Details geçirilen anahtar değeri yol verilerinden gelir. Yönlendirme verileri, model bağlayıcısının URL'nin bir kesiminde bulduğu verilerdir. Örneğin, varsayılan yol denetleyici, eylem ve kimlik kesimlerini belirtir:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
});

Aşağıdaki URL'de varsayılan yol Eğitmen'i denetleyici, Eylem olarak Dizin'i ve kimlik olarak 1'i eşler; bunlar rota verisi değerleridir.

http://localhost:1230/Instructor/Index/1?courseID=2021

URL'nin ("?courseID=2021") son bölümü bir sorgu dizesi değeridir. Model bağlayıcısı, id değerini sorgu dizesi değeri Index olarak geçirirseniz yöntem id parametresine de geçirir:

http://localhost:1230/Instructor/Index?id=1&CourseID=2021

Dizin sayfasında, köprü URL'leri görünümdeki Razor etiket yardımcı deyimleri tarafından oluşturulur. Aşağıdaki Razor kodda id parametresi varsayılan yol ile eşleşir, bu nedenle id yol verilerine eklenir.

<a asp-action="Edit" asp-route-id="@item.ID">Edit</a>

Bu, 6 olduğunda item.ID aşağıdaki HTML'yi oluşturur:

<a href="/Students/Edit/6">Edit</a>

Aşağıdaki Razor kodda, studentID varsayılan yoldaki bir parametreyle eşleşmediğinden sorgu dizesi olarak eklenir.

<a asp-action="Edit" asp-route-studentID="@item.ID">Edit</a>

Bu, 6 olduğunda item.ID aşağıdaki HTML'yi oluşturur:

<a href="/Students/Edit?studentID=6">Edit</a>

Etiket yardımcıları hakkında daha fazla bilgi için bkz . ASP.NET Core'da Etiket Yardımcıları.

Ayrıntılar görünümüne kayıt ekleme

Views/Students/Details.cshtml'ı açın. Her alan, aşağıdaki örnekte gösterildiği gibi ve DisplayFor yardımcıları kullanılarak DisplayNameFor görüntülenir:

<dt class="col-sm-2">
    @Html.DisplayNameFor(model => model.LastName)
</dt>
<dd class="col-sm-10">
    @Html.DisplayFor(model => model.LastName)
</dd>

Son alandan sonra ve kapanış </dl> etiketinden hemen önce, kayıtların listesini görüntülemek için aşağıdaki kodu ekleyin:

<dt class="col-sm-2">
    @Html.DisplayNameFor(model => model.Enrollments)
</dt>
<dd class="col-sm-10">
    <table class="table">
        <tr>
            <th>Course Title</th>
            <th>Grade</th>
        </tr>
        @foreach (var item in Model.Enrollments)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.Course.Title)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Grade)
                </td>
            </tr>
        }
    </table>
</dd>

Kodu yapıştırdıktan sonra kod girintisi yanlışsa, düzeltmek için CTRL-K-D tuşlarına basın.

Bu kod, gezinti özelliğindeki Enrollments varlıklar arasında döngü oluşturur. Her kayıt için kurs başlığını ve notu görüntüler. Kurs başlığı, Kayıtlar varlığının gezinti özelliğinde Course depolanan Kurs varlığından alınır.

Uygulamayı çalıştırın, Öğrenciler sekmesini seçin ve bir öğrencinin Ayrıntılar bağlantısına tıklayın. Seçilen öğrencinin ders ve not listesini görürsünüz:

Student Details page

Oluştur sayfasını güncelleştirme

içindeStudentsController.cs, try-catch bloğu ekleyerek ve özniteliğinden Bind kimliği kaldırarak HttpPost Create yöntemini değiştirin.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(
    [Bind("EnrollmentDate,FirstMidName,LastName")] Student student)
{
    try
    {
        if (ModelState.IsValid)
        {
            _context.Add(student);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
    }
    catch (DbUpdateException /* ex */)
    {
        //Log the error (uncomment ex variable name and write a log.
        ModelState.AddModelError("", "Unable to save changes. " +
            "Try again, and if the problem persists " +
            "see your system administrator.");
    }
    return View(student);
}

Bu kod, ASP.NET Core MVC model bağlayıcısı tarafından oluşturulan Öğrenci varlığını Öğrenciler varlık kümesine ekler ve ardından değişiklikleri veritabanına kaydeder. (Model bağlayıcısı, form tarafından gönderilen verilerle çalışmanızı kolaylaştıran ASP.NET Core MVC işlevselliğini ifade eder; model bağlayıcısı gönderilen form değerlerini CLR türlerine dönüştürür ve bunları parametrelerdeki eylem yöntemine geçirir. Bu durumda model bağlayıcısı, Form koleksiyonundaki özellik değerlerini kullanarak sizin için bir Student varlığının örneğini oluşturur.)

Kimlik, satır eklendiğinde SQL Server'ın otomatik olarak ayarlanacağı birincil anahtar değeri olduğundan özniteliğinden Bind kaldırdınızID. Kullanıcıdan gelen giriş kimlik değerini ayarlamaz.

özniteliği dışında Bind , iskelesi oluşturulmuş kodda yaptığınız tek değişiklik try-catch bloğudur. Değişiklikleri kaydedilirken türetilen DbUpdateException bir özel durum yakalanırsa, genel bir hata iletisi görüntülenir. DbUpdateException özel durumlar bazen programlama hatası yerine uygulamanın dışındaki bir şeyden kaynaklanır, bu nedenle kullanıcının yeniden denemesi tavsiye edilir. Bu örnekte uygulanmasa da, bir üretim kalitesi uygulaması özel durumu günlüğe kaydeder. Daha fazla bilgi için İzleme ve Telemetri (Azure ile Gerçek Dünya Bulut Uygulamaları Oluşturma) bölümündeki İçgörü günlüğü bölümüne bakın.

özniteliği siteler ValidateAntiForgeryToken arası istek sahteciliği (CSRF) saldırılarını önlemeye yardımcı olur. Belirteç, FormTagHelper tarafından görünüme otomatik olarak eklenir ve form kullanıcı tarafından gönderildiğinde eklenir. Belirteç özniteliği tarafından ValidateAntiForgeryToken doğrulanır. Daha fazla bilgi için, bkz. ASP.NET Core'da Siteler Arası İstek Sahteciliği (XSRF/CSRF) saldırılarını önleme.

Fazla paylaşımla ilgili güvenlik notu

Bind yapı iskelesi oluşturulmuş kodun yönteminde Create içerdiği öznitelik, oluşturma senaryolarında aşırı paylaşıma karşı korumanın bir yoludur. Örneğin, Öğrenci varlığının bu web sayfasının ayarlamasını istemediğiniz bir Secret özellik içerdiğini varsayalım.

public class Student
{
    public int ID { get; set; }
    public string LastName { get; set; }
    public string FirstMidName { get; set; }
    public DateTime EnrollmentDate { get; set; }
    public string Secret { get; set; }
}

Web sayfasında bir Secret alanınız olmasa bile, bir bilgisayar korsanı form değeri göndermek Secret için Fiddler gibi bir araç kullanabilir veya javascript yazabilir. Bind Öznitelik, model bağlayıcısının Öğrenci örneği oluştururken kullandığı alanları sınırlamadan, model bağlayıcısı bu Secret form değerini alır ve Student varlık örneğini oluşturmak için kullanır. Ardından, hacker'ın form alanı için Secret belirttiği değer veritabanınızda güncelleştirilir. Aşağıdaki görüntüde, fiddler aracının gönderilen form değerlerine Secret alanı ("OverPost" değeriyle) eklemesi gösterilmektedir.

Fiddler adding Secret field

"OverPost" değeri daha sonra eklenen satırın Secret özelliğine başarıyla eklenir, ancak web sayfasının bu özelliği ayarlayabilmesini hiç amaçlamadıysanız.

Düzenleme senaryolarında, varlığı önce veritabanından okuyup, sonra açıkça izin verilen özellikler listesini geçirerek çağırarak TryUpdateModelfazla paylaşım yapılmasını önleyebilirsiniz. Bu, bu öğreticilerde kullanılan yöntemdir.

Birçok geliştirici tarafından tercih edilen fazla göndermeyi önlemenin alternatif bir yolu, model bağlama ile varlık sınıfları yerine görünüm modellerini kullanmaktır. Görünüm modeline yalnızca güncelleştirmek istediğiniz özellikleri ekleyin. MVC model bağlayıcısı tamamlandıktan sonra, isteğe bağlı olarak AutoMapper gibi bir araç kullanarak görünüm modeli özelliklerini varlık örneğine kopyalayın. Varlık örneğinde durumunu olarak ve Unchangedardından görünüm modeline dahil edilen her varlık özelliğinde true olarak ayarlamak Property("PropertyName").IsModified için kullanın_context.Entry. Bu yöntem hem düzenleme hem de oluşturma senaryolarında çalışır.

Oluştur sayfasını test edin

içindeki Views/Students/Create.cshtml kod, her alan için , inputve span (doğrulama iletileri için) etiket yardımcılarını kullanırlabel.

Uygulamayı çalıştırın, Öğrenciler sekmesini seçin ve Yeni Oluştur'a tıklayın.

Adları ve tarihi girin. Tarayıcınız bunu yapmanıza izin veriyorsa geçersiz bir tarih girmeyi deneyin. (Bazı tarayıcılar sizi tarih seçici kullanmaya zorlar.) Ardından, hata iletisini görmek için Oluştur'a tıklayın.

Date validation error

Bu, varsayılan olarak elde ettiğiniz sunucu tarafı doğrulamadır; sonraki bir öğreticide, istemci tarafı doğrulaması için kod oluşturacak özniteliklerin nasıl ekleneceğini göreceksiniz. Aşağıdaki vurgulanmış kod, yöntemindeki model doğrulama denetimini Create gösterir.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(
    [Bind("EnrollmentDate,FirstMidName,LastName")] Student student)
{
    try
    {
        if (ModelState.IsValid)
        {
            _context.Add(student);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
    }
    catch (DbUpdateException /* ex */)
    {
        //Log the error (uncomment ex variable name and write a log.
        ModelState.AddModelError("", "Unable to save changes. " +
            "Try again, and if the problem persists " +
            "see your system administrator.");
    }
    return View(student);
}

Tarihi geçerli bir değerle değiştirin ve Yeni öğrencinin Dizin sayfasında görünmesi için Oluştur'a tıklayın.

Düzenle sayfasını güncelleştirme

içinde StudentController.csHttpGet Edit yöntemi (özniteliği olmayanHttpPost) yönteminde gördüğünüz Details gibi seçili Student varlığını almak için yöntemini kullanırFirstOrDefaultAsync. Bu yöntemi değiştirmeniz gerekmez.

HttpPost Edit eylem yöntemini aşağıdaki kodla değiştirin.

[HttpPost, ActionName("Edit")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EditPost(int? id)
{
    if (id == null)
    {
        return NotFound();
    }
    var studentToUpdate = await _context.Students.FirstOrDefaultAsync(s => s.ID == id);
    if (await TryUpdateModelAsync<Student>(
        studentToUpdate,
        "",
        s => s.FirstMidName, s => s.LastName, s => s.EnrollmentDate))
    {
        try
        {
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        catch (DbUpdateException /* ex */)
        {
            //Log the error (uncomment ex variable name and write a log.)
            ModelState.AddModelError("", "Unable to save changes. " +
                "Try again, and if the problem persists, " +
                "see your system administrator.");
        }
    }
    return View(studentToUpdate);
}

Bu değişiklikler, fazla paylaşım yapılmasını önlemek için en iyi güvenlik uygulamasını uygular. İskele bir Bind öznitelik oluşturdu ve model bağlayıcısı tarafından oluşturulan varlığı bir Modified bayrakla varlık kümesine ekledi. Özniteliği parametrede listelenmeyen Bind Include alanlardaki önceden var olan verileri temizlediğinden bu kod birçok senaryo için önerilmez.

Yeni kod, mevcut varlığı okur ve gönderilen form verilerindeki kullanıcı girişine göre alınan varlıktaki alanları güncelleştirmek için çağrılarTryUpdateModel. Entity Framework'ün otomatik değişiklik izlemesi, form girişi tarafından değiştirilen alanlarda bayrağı ayarlar Modified . SaveChanges Yöntemi çağrıldığında, Entity Framework veritabanı satırını güncelleştirmek için SQL deyimleri oluşturur. Eşzamanlılık çakışmaları yoksayılır ve veritabanında yalnızca kullanıcı tarafından güncelleştirilen tablo sütunları güncelleştirilir. (Sonraki bir öğreticide eşzamanlılık çakışmalarının nasıl işleneceğini gösterilmektedir.)

Fazla göndermeyi önlemek için en iyi yöntem olarak, Düzenle sayfası tarafından güncelleştirilebilir olmasını istediğiniz alanlar parametrelerde TryUpdateModel bildirilir. (Parametre listesindeki alan listesinden önce gelen boş dize, form alanları adlarıyla kullanılacak bir ön ek içindir.) Şu anda koruduğun ek alan yok, ancak model bağlayıcısının bağlamasını istediğiniz alanları listelemek, gelecekte veri modeline alanlar eklerseniz, bunları buraya açıkça ekleyene kadar bunların otomatik olarak korunmasını sağlar.

Bu değişikliklerin sonucunda, HttpPost Edit yönteminin yöntem imzası HttpGet Edit yöntemiyle aynıdır; bu nedenle yöntemini EditPostyeniden adlandırmışsınızdır.

Alternatif HttpPost Düzenleme kodu: Oluşturma ve ekleme

Önerilen HttpPost düzenleme kodu, yalnızca değiştirilen sütunların güncelleştirilmesini sağlar ve model bağlama için eklenmesini istemediğiniz özelliklerdeki verileri korur. Ancak, ilk okuma yaklaşımı fazladan bir veritabanı okuması gerektirir ve eşzamanlılık çakışmalarını işlemek için daha karmaşık bir koda neden olabilir. Alternatif olarak, model bağlayıcısı tarafından oluşturulan bir varlığı EF bağlamı'na iliştirip değiştirilmiş olarak işaretlemek de kullanılabilir. (Projenizi bu kodla güncelleştirin, yalnızca isteğe bağlı bir yaklaşımı göstermek için gösterilir.)

public async Task<IActionResult> Edit(int id, [Bind("ID,EnrollmentDate,FirstMidName,LastName")] Student student)
{
    if (id != student.ID)
    {
        return NotFound();
    }
    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(student);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        catch (DbUpdateException /* ex */)
        {
            //Log the error (uncomment ex variable name and write a log.)
            ModelState.AddModelError("", "Unable to save changes. " +
                "Try again, and if the problem persists, " +
                "see your system administrator.");
        }
    }
    return View(student);
}

Web sayfası kullanıcı arabirimi varlıktaki tüm alanları içerdiğinde ve bunlardan herhangi birini güncelleştirebildiğinde bu yaklaşımı kullanabilirsiniz.

yapı iskelesi oluşturulmuş kod oluşturma ve ekleme yaklaşımını kullanır, ancak yalnızca özel durumları yakalar DbUpdateConcurrencyException ve 404 hata kodu döndürür. Gösterilen örnek tüm veritabanı güncelleştirme özel durumlarını yakalar ve bir hata iletisi görüntüler.

Varlık Durumları

Veritabanı bağlamı, bellekteki varlıkların veritabanında karşılık gelen satırlarıyla eşitlenip eşitlenmediğini izler ve bu bilgiler yöntemi çağırdığınızda SaveChanges ne olacağını belirler. Örneğin, yöntemine Add yeni bir varlık geçirdiğinizde, bu varlığın durumu olarak Addedayarlanır. Ardından yöntemini çağırdığınızda SaveChanges veritabanı bağlamı bir SQL INSERT komutu döndürür.

Bir varlık aşağıdaki durumlardan birinde olabilir:

  • Added. Varlık henüz veritabanında yok. SaveChanges yöntemi bir INSERT deyimi oluşturur.

  • Unchanged. yöntemiyle bu varlıkla SaveChanges hiçbir şey yapılmasına gerek yoktur. Veritabanından bir varlığı okuduğunuzda varlık bu durumla başlar.

  • Modified. Varlığın özellik değerlerinin bazıları veya tümü değiştirildi. SaveChanges yöntemi bir UPDATE deyimi oluşturur.

  • Deleted. Varlık silinmek üzere işaretlendi. SaveChanges yöntemi bir DELETE deyimi oluşturur.

  • Detached. Varlık veritabanı bağlamı tarafından izlenmiyor.

Masaüstü uygulamasında durum değişiklikleri genellikle otomatik olarak ayarlanır. Bir varlığı okur ve bazı özellik değerlerinde değişiklik yaparsınız. Bu, varlık durumunun otomatik olarak olarak olarak değiştirilmesine Modifiedneden olur. Ardından çağırdığınızda SaveChanges, Entity Framework yalnızca değiştirdiğiniz gerçek özellikleri güncelleştiren bir SQL UPDATE deyimi oluşturur.

Bir web uygulamasında, DbContext başlangıçta bir varlığı okuyan ve düzenlenecek verilerini görüntüleyen, sayfa işlendikten sonra atılır. HttpPost Edit eylem yöntemi çağrıldığında, yeni bir web isteği yapılır ve yeni bir örneğine DbContextsahipsiniz. Varlığı bu yeni bağlamda yeniden okursanız masaüstü işleme benzetimi yapılır.

Ancak ek okuma işlemini yapmak istemiyorsanız, model bağlayıcısı tarafından oluşturulan varlık nesnesini kullanmanız gerekir. Bunu yapmanın en basit yolu, daha önce gösterilen alternatif HttpPost Düzenleme kodunda olduğu gibi varlık durumunu Değiştirildi olarak ayarlamaktır. Ardından öğesini çağırdığınızda SaveChanges, bağlamın hangi özellikleri değiştirdiğiniz hakkında hiçbir bilgisi olmadığından Entity Framework veritabanı satırının tüm sütunlarını güncelleştirir.

İlk okuma yaklaşımından kaçınmak, ancak SQL UPDATE deyiminin yalnızca kullanıcının gerçekten değiştirdiği alanları güncelleştirmesini istiyorsanız, kod daha karmaşıktır. HttpPost Edit yöntemi çağrıldığında kullanılabilir olmaları için özgün değerleri bir şekilde (örneğin, gizli alanları kullanarak) kaydetmeniz gerekir. Ardından, özgün değerleri kullanarak bir Student varlığı oluşturabilir, varlığın Attach özgün sürümüyle yöntemini çağırabilir, varlığın değerlerini yeni değerlerle güncelleştirebilir ve ardından öğesini çağırabilirsiniz SaveChanges.

Düzenleme sayfasını test edin

Uygulamayı çalıştırın, Öğrenciler sekmesini seçin ve ardından Bir Köprüyü düzenle'ye tıklayın.

Students edit page

Bazı verileri değiştirin ve Kaydet'e tıklayın. Dizin sayfası açılır ve değiştirilen verileri görürsünüz.

Sil sayfasını güncelleştirme

içinde StudentController.cs, HttpGet Delete yönteminin şablon kodu, Ayrıntılar ve Düzenleme yöntemlerinde gördüğünüz gibi seçili Student varlığını almak için yöntemini kullanır FirstOrDefaultAsync . Ancak çağrısı başarısız olduğunda özel bir hata iletisi uygulamak için SaveChanges bu yönteme ve ilgili görünümüne bazı işlevler ekleyeceksiniz.

Güncelleştirme ve oluşturma işlemlerini gördüğünüz gibi silme işlemleri için iki eylem yöntemi gerekir. GET isteğine yanıt olarak çağrılan yöntem, kullanıcıya silme işlemini onaylama veya iptal etme şansı veren bir görünüm görüntüler. Kullanıcı onaylarsa bir POST isteği oluşturulur. Böyle bir durumda HttpPost Delete yöntemi çağrılır ve bu yöntem silme işlemini gerçekleştirir.

Veritabanı güncelleştirildiğinde oluşabilecek hataları işlemek için HttpPost Delete yöntemine bir try-catch bloğu ekleyeceksiniz. Bir hata oluşursa, HttpPost Delete yöntemi HttpGet Delete yöntemini çağırır ve bir hata oluştuğuna işaret eden bir parametre iletir. HttpGet Delete yöntemi daha sonra hata iletisiyle birlikte onay sayfasını yeniden dağıtarak kullanıcıya iptal etme veya yeniden deneme fırsatı verir.

HttpGet Delete eylem yöntemini, hata raporlamayı yöneten aşağıdaki kodla değiştirin.

public async Task<IActionResult> Delete(int? id, bool? saveChangesError = false)
{
    if (id == null)
    {
        return NotFound();
    }

    var student = await _context.Students
        .AsNoTracking()
        .FirstOrDefaultAsync(m => m.ID == id);
    if (student == null)
    {
        return NotFound();
    }

    if (saveChangesError.GetValueOrDefault())
    {
        ViewData["ErrorMessage"] =
            "Delete failed. Try again, and if the problem persists " +
            "see your system administrator.";
    }

    return View(student);
}

Bu kod, yöntemin değişiklikleri kaydetme hatasından sonra çağrılıp çağrılmadığını gösteren isteğe bağlı bir parametreyi kabul eder. HttpGet Delete yöntemi önceki bir hata olmadan çağrıldığında bu parametre false olur. Veritabanı güncelleştirme hatasına yanıt olarak HttpPost Delete yöntemi tarafından çağrıldığında parametresi true olur ve görünüme bir hata iletisi geçirilir.

HttpPost Delete'e ilk okuma yaklaşımı

HttpPost Delete eylem yöntemini (adlı DeleteConfirmed) gerçek silme işlemini gerçekleştiren ve veritabanı güncelleştirme hatalarını yakalayan aşağıdaki kodla değiştirin.

[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
    var student = await _context.Students.FindAsync(id);
    if (student == null)
    {
        return RedirectToAction(nameof(Index));
    }

    try
    {
        _context.Students.Remove(student);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    catch (DbUpdateException /* ex */)
    {
        //Log the error (uncomment ex variable name and write a log.)
        return RedirectToAction(nameof(Delete), new { id = id, saveChangesError = true });
    }
}

Bu kod seçili varlığı alır ve varlığın Remove durumunu Deletedolarak ayarlamak için yöntemini çağırır. Çağrıldığında SaveChanges bir SQL DELETE komutu oluşturulur.

HttpPost Delete'e oluşturma ve ekleme yaklaşımı

Yüksek hacimli bir uygulamada performansı geliştirmek öncelikliyse, yalnızca birincil anahtar değerini kullanarak bir Student varlığının örneğini oluşturup varlık durumunu Deletedolarak ayarlayarak gereksiz bir SQL sorgusundan kaçınabilirsiniz. Varlığı silmek için Entity Framework'e gerekenler bunlardır. (Bu kodu projenize koymayın; yalnızca alternatif bir kod göstermek için buradadır.)

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
    try
    {
        Student studentToDelete = new Student() { ID = id };
        _context.Entry(studentToDelete).State = EntityState.Deleted;
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    catch (DbUpdateException /* ex */)
    {
        //Log the error (uncomment ex variable name and write a log.)
        return RedirectToAction(nameof(Delete), new { id = id, saveChangesError = true });
    }
}

Varlığın da silinmesi gereken ilgili verileri varsa, veritabanında art arda silmenin yapılandırıldığından emin olun. Varlık silmeye yönelik bu yaklaşımla EF, silinecek ilgili varlıklar olduğunu fark etmeyebilir.

Sil görünümünü güncelleştirme

içinde Views/Student/Delete.cshtml, aşağıdaki örnekte gösterildiği gibi h2 başlığı ile h3 başlığı arasına bir hata iletisi ekleyin:

<h2>Delete</h2>
<p class="text-danger">@ViewData["ErrorMessage"]</p>
<h3>Are you sure you want to delete this?</h3>

Uygulamayı çalıştırın, Öğrenciler sekmesini seçin ve Bir Köprüyü sil'e tıklayın:

Delete confirmation page

Sil'e tıklayın. Dizin sayfası, silinen öğrenci olmadan görüntülenir. (Eşzamanlılık öğreticisinde hata işleme kodunun bir örneğini çalışır durumda görürsünüz.)

Veritabanı bağlantılarını kapatma

Veritabanı bağlantısının barındırıldığı kaynakları boşaltmak için, bağlam örneğinin işiniz bittiğinde mümkün olan en kısa sürede atılması gerekir. ASP.NET Core yerleşik bağımlılık ekleme işlemi bu görevi sizin için halleder.

içindeStartup.cs, sınıfı ASP.NET Core DI kapsayıcısında sağlamak DbContext için AddDbContext uzantısı yöntemini çağırırsınız. Bu yöntem, hizmet ömrünü varsayılan olarak olarak Scoped olarak ayarlar. Scoped , bağlam nesnesinin yaşam süresinin web isteği yaşam süresiyle aynı olduğu ve yöntemin Dispose web isteğinin sonunda otomatik olarak çağrılacağı anlamına gelir.

İşlemleri işleme

Varsayılan olarak Entity Framework işlemleri örtük olarak uygular. Birden çok satır veya tabloda değişiklik yaptığınız ve ardından öğesini çağırdığınız SaveChangessenaryolarda, Entity Framework otomatik olarak tüm değişikliklerinizin başarılı olmasını veya tümünün başarısız olmasını sağlar. Önce bazı değişiklikler yapılır ve sonra bir hata oluşursa, bu değişiklikler otomatik olarak geri alınır. Daha fazla denetime ihtiyacınız olan senaryolar için (örneğin, bir işleme Entity Framework dışında yapılan işlemleri dahil etmek istiyorsanız) bkz . İşlemler.

İzlemesiz sorgular

Veritabanı bağlamı tablo satırlarını aldığında ve bunları temsil eden varlık nesneleri oluşturduğunda, varsayılan olarak bellekteki varlıkların veritabanındakilerle eşitlenmiş olup olmadığını izler. Bellekteki veriler önbellek görevi görür ve varlığı güncelleştirdiğinizde kullanılır. Bağlam örnekleri genellikle kısa süreli (her istek için yeni bir tane oluşturulur ve atılır) ve bir varlığı okuyan bağlam genellikle bu varlık yeniden kullanılmadan önce atıldığından, bu önbelleğe alma genellikle bir web uygulamasında gereksizdir.

yöntemini çağırarak bellekteki varlık nesnelerinin izlenmesini AsNoTracking devre dışı bırakabilirsiniz. Bunu yapmak isteyebileceğiniz tipik senaryolar şunlardır:

  • Bağlam ömrü boyunca hiçbir varlığı güncelleştirmeniz gerekmez ve EF'nin gezinti özelliklerini ayrı sorgular tarafından alınan varlıklarla otomatik olarak yüklemesi gerekmez. Bu koşullar genellikle denetleyicinin HttpGet eylem yöntemlerinde karşılanıyor.

  • Büyük miktarda veri alan bir sorgu çalıştırıyorsanız, döndürülen verilerin yalnızca küçük bir kısmı güncelleştirilecektir. Büyük sorgu için izlemeyi kapatmak ve daha sonra güncelleştirililmesi gereken birkaç varlık için bir sorgu çalıştırmak daha verimli olabilir.

  • Güncelleştirmek için bir varlık eklemek istiyorsunuz, ancak daha önce aynı varlığı farklı bir amaç için aldıysanız. Varlık veritabanı bağlamı tarafından zaten izlendiğinden, değiştirmek istediğiniz varlığı ekleyemezsiniz. Bu durumu işlemenin bir yolu, önceki sorguda çağırmaktır AsNoTracking .

Daha fazla bilgi için bkz . İzleme ve İzleme Yok.

Kodu alma

Tamamlanan uygulamayı indirin veya görüntüleyin.

Sonraki adımlar

Bu öğreticide şunları yaptınız:

  • Ayrıntılar sayfası özelleştirildi
  • Oluştur sayfası güncelleştirildi
  • Düzenle sayfası güncelleştirildi
  • Sil sayfası güncelleştirildi
  • Kapalı veritabanı bağlantıları

Sıralama, filtreleme ve sayfalama ekleyerek Dizin sayfasının işlevselliğini genişletmeyi öğrenmek için sonraki öğreticiye ilerleyin.