ASP.NET MVC uygulamasındaki Entity Framework Ilişkili verileri güncelleştirme (6/10)Updating Related Data with the Entity Framework in an ASP.NET MVC Application (6 of 10)

Tom Dykstra tarafındanby Tom Dykstra

Tamamlanmış projeyi indirDownload Completed Project

Contoso Üniversitesi örnek Web uygulaması, Entity Framework 5 Code First ve Visual Studio 2012 kullanarak nasıl ASP.NET MVC 4 uygulamaları oluşturacağınızı gösterir.The Contoso University sample web application demonstrates how to create ASP.NET MVC 4 applications using the Entity Framework 5 Code First and Visual Studio 2012. Öğretici serisi hakkında daha fazla bilgi için, serideki ilk öğreticiyebakın.For information about the tutorial series, see the first tutorial in the series. Öğretici serisini başlangıçtan başlatabilir veya Bu bölüm için bir başlangıç projesi indirebilir ve buradan başlayabilirsiniz.You can start the tutorial series from the beginning or download a starter project for this chapter and start here.

Note

Giderebileceğiniz bir sorunla karşılaşırsanız, Tamamlanan bölümü indirin ve sorununuzu yeniden oluşturmaya çalışın.If you run into a problem you can't resolve, download the completed chapter and try to reproduce your problem. Sorunu, kodunuzun tamamlanan kodla karşılaştırarak genellikle soruna çözüm olarak ulaşabilirsiniz.You can generally find the solution to the problem by comparing your code to the completed code. Bazı yaygın hatalar ve bunların nasıl çözüleceği için bkz . hatalar ve geçici çözümler.For some common errors and how to solve them, see Errors and Workarounds.

Önceki öğreticide ilgili verileri görüntülediyseniz; Bu öğreticide ilgili verileri güncelleştireceksiniz.In the previous tutorial you displayed related data; in this tutorial you'll update related data. Çoğu ilişki için, bu, uygun yabancı anahtar alanları güncelleştirilerek yapılabilir.For most relationships, this can be done by updating the appropriate foreign key fields. Çoka çok ilişkiler için Entity Framework, JOIN tablosunu doğrudan kullanıma sunmaz, bu nedenle, uygun gezinti özelliklerine ve içindeki varlıkları açıkça eklemeniz ve kaldırmanız gerekir.For many-to-many relationships, the Entity Framework doesn't expose the join table directly, so you must explicitly add and remove entities to and from the appropriate navigation properties.

Aşağıdaki çizimlerde, birlikte çalışacağımız sayfalar gösterilmektedir.The following illustrations show the pages that you'll work with.

Course_create_page

Instructor_edit_page_with_courses

Kurslar için oluşturma ve düzenleme sayfalarını özelleştirmeCustomize the Create and Edit Pages for Courses

Yeni bir kurs varlığı oluşturulduğunda, mevcut bir departmanla bir ilişkisi olmalıdır.When a new course entity is created, it must have a relationship to an existing department. Bunu kolaylaştırmak için, yapı iskelesi kodu denetleyici yöntemlerini içerir ve departmanı seçmeye yönelik bir açılan liste içeren görünümler oluşturup düzenleyebilir.To facilitate this, the scaffolded code includes controller methods and Create and Edit views that include a drop-down list for selecting the department. Açılan liste Course.DepartmentID yabancı anahtar özelliğini ayarlar ve bu, Department gezinti özelliğini uygun Department varlığıyla yüklemek için tüm Entity Framework gereksinimlidir.The drop-down list sets the Course.DepartmentID foreign key property, and that's all the Entity Framework needs in order to load the Department navigation property with the appropriate Department entity. Scafkatmış kodu kullanacaksınız, ancak hata işleme eklemek ve açılan listeyi sıralamak için biraz değişiklik yapacaksınız.You'll use the scaffolded code, but change it slightly to add error handling and sort the drop-down list.

CourseController.cs' de, dört Edit ve Create yöntemleri silin ve bunları şu kodla değiştirin:In CourseController.cs, delete the four Edit and Create methods and replace them with the following code:

public ActionResult Create()
{
   PopulateDepartmentsDropDownList();
   return View();
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(
   [Bind(Include = "CourseID,Title,Credits,DepartmentID")]
   Course course)
{
   try
   {
      if (ModelState.IsValid)
      {
         db.Courses.Add(course);
         db.SaveChanges();
         return RedirectToAction("Index");
      }
   }
   catch (DataException /* dex */)
   {
      //Log the error (uncomment dex variable name after DataException and add a line here to write a log.)
      ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
   }
   PopulateDepartmentsDropDownList(course.DepartmentID);
   return View(course);
}

public ActionResult Edit(int id)
{
   Course course = db.Courses.Find(id);
   PopulateDepartmentsDropDownList(course.DepartmentID);
   return View(course);
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(
    [Bind(Include = "CourseID,Title,Credits,DepartmentID")]
    Course course)
{
   try
   {
      if (ModelState.IsValid)
      {
         db.Entry(course).State = EntityState.Modified;
         db.SaveChanges();
         return RedirectToAction("Index");
      }
   }
   catch (DataException /* dex */)
   {
      //Log the error (uncomment dex variable name after DataException and add a line here to write a log.)
      ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
   }
   PopulateDepartmentsDropDownList(course.DepartmentID);
   return View(course);
}

private void PopulateDepartmentsDropDownList(object selectedDepartment = null)
{
   var departmentsQuery = from d in db.Departments
                          orderby d.Name
                          select d;
   ViewBag.DepartmentID = new SelectList(departmentsQuery, "DepartmentID", "Name", selectedDepartment);
} 

PopulateDepartmentsDropDownList yöntemi, ada göre sıralanmış tüm bölümlerin bir listesini alır, açılan liste için bir SelectList koleksiyonu oluşturur ve koleksiyonu bir ViewBag özelliğindeki görünüme geçirir.The PopulateDepartmentsDropDownList method gets a list of all departments sorted by name, creates a SelectList collection for a drop-down list, and passes the collection to the view in a ViewBag property. Yöntemi, çağıran kodun, açılan liste işlendiğinde seçilecek öğeyi belirtmesini sağlayan isteğe bağlı selectedDepartment parametresini kabul eder.The method accepts the optional selectedDepartment parameter that allows the calling code to specify the item that will be selected when the drop-down list is rendered. Görünüm adı DepartmentID DropDownList Yardımcısı' na geçecek ve yardımcı sonra ViewBag nesnesine DepartmentIDadlı bir SelectList bakabilecektir.The view will pass the name DepartmentID to the DropDownList helper, and the helper then knows to look in the ViewBag object for a SelectList named DepartmentID.

HttpGet Create yöntemi, seçilen öğeyi ayarlamadan PopulateDepartmentsDropDownList yöntemini çağırır, çünkü yeni bir kurs için departman henüz kurulmadı:The HttpGet Create method calls the PopulateDepartmentsDropDownList method without setting the selected item, because for a new course the department is not established yet:

public ActionResult Create()
{
    PopulateDepartmentsDropDownList();
    return View();
}

HttpGet Edit yöntemi, düzenlenen kursa zaten atanmış departmanın KIMLIğINE bağlı olarak seçili öğeyi ayarlar:The HttpGet Edit method sets the selected item, based on the ID of the department that is already assigned to the course being edited:

public ActionResult Edit(int id)
{
    Course course = db.Courses.Find(id);
    PopulateDepartmentsDropDownList(course.DepartmentID);
    return View(course);
}

Hem Create hem de Edit için HttpPost yöntemleri, bir hatadan sonra sayfayı yeniden görüntülerken seçili öğeyi ayarlayan kodu içerir:The HttpPost methods for both Create and Edit also include code that sets the selected item when they redisplay the page after an error:

catch (DataException /* dex */)
{
    //Log the error (uncomment dex variable name after DataException and add a line here to write a log.)
    ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
PopulateDepartmentsDropDownList(course.DepartmentID);
return View(course);

Bu kod, sayfa hata iletisini göstermek için yeniden görüntülendiğinde, seçilen bölümün seçili kalırsa emin olmanızı sağlar.This code ensures that when the page is redisplayed to show the error message, whatever department was selected stays selected.

Views\course\create.exe' de, başlık alanından önce yeni bir kurs numarası alanı oluşturmak için vurgulanan kodu ekleyin.In Views\Course\Create.cshtml, add the highlighted code to create a new course number field before the Title field. Önceki bir öğreticide açıklandığı gibi, birincil anahtar alanları varsayılan olarak iskele değildir, ancak bu birincil anahtar anlamlı olduğundan kullanıcının anahtar değerini girebilmesini istersiniz.As explained in an earlier tutorial, primary key fields aren't scaffolded by default, but this primary key is meaningful, so you want the user to be able to enter the key value.

@model ContosoUniversity.Models.Course

@{
    ViewBag.Title = "Create";
}

<h2>Create</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Course</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.CourseID)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.CourseID)
            @Html.ValidationMessageFor(model => model.CourseID)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Title)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Title)
            @Html.ValidationMessageFor(model => model.Title)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Credits)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Credits)
            @Html.ValidationMessageFor(model => model.Credits)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.DepartmentID, "Department")
        </div>
        <div class="editor-field">
            @Html.DropDownList("DepartmentID", String.Empty)
            @Html.ValidationMessageFor(model => model.DepartmentID)
        </div>

        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Views\course\edit.exe, Views\course\delete.exeve Views\course\details.cshtmliçinde başlık alanından önce bir kurs numarası alanı ekleyin.In Views\Course\Edit.cshtml, Views\Course\Delete.cshtml, and Views\Course\Details.cshtml, add a course number field before the Title field. Birincil anahtar olduğundan, görüntülenir, ancak değiştirilemez.Because it's the primary key, it's displayed, but it can't be changed.

<div class="editor-label">
    @Html.LabelFor(model => model.CourseID)
</div>
<div class="editor-field">
    @Html.DisplayFor(model => model.CourseID)
</div>

Oluştur sayfasını çalıştırın (kurs dizinini görüntüle sayfasını ve Yeni oluştur' a tıklayın) ve yeni bir kurs için veri girin:Run the Create page (display the Course Index page and click Create New) and enter data for a new course:

Course_create_page

Oluştur'u tıklatın.Click Create. Kurs dizini sayfası, listeye eklenen yeni kursla birlikte görüntülenir.The Course Index page is displayed with the new course added to the list. Dizin sayfası listesindeki departman adı, ilişkinin doğru şekilde oluşturulduğunu gösteren gezinti özelliğinden gelir.The department name in the Index page list comes from the navigation property, showing that the relationship was established correctly.

Course_Index_page_showing_new_course

Düzenleme sayfasını çalıştırın (kurs dizinini görüntüleyin ve bir kurs üzerinde Düzenle ' ye tıklayın).Run the Edit page (display the Course Index page and click Edit on a course).

Course_edit_page

Sayfadaki verileri değiştirin ve Kaydet' e tıklayın.Change data on the page and click Save. Kurs dizini sayfası, güncelleştirilmiş kurs verileriyle birlikte görüntülenir.The Course Index page is displayed with the updated course data.

Eğitmenler için düzenleme sayfası eklemeAdding an Edit Page for Instructors

Bir eğitmen kaydını düzenlediğinizde, eğitmenin Office atamasını güncelleştirebilmek istersiniz.When you edit an instructor record, you want to be able to update the instructor's office assignment. Instructor varlığı, OfficeAssignment varlığı ile bire sıfır veya-arasında bir ilişkiye sahiptir; yani aşağıdaki durumları işlemeniz gerekir:The Instructor entity has a one-to-zero-or-one relationship with the OfficeAssignment entity, which means you must handle the following situations:

  • Kullanıcı Office atamasını temizlediğinde ve başlangıçta bir değer içeriyorsa, OfficeAssignment varlığını kaldırmanız ve silmeniz gerekir.If the user clears the office assignment and it originally had a value, you must remove and delete the OfficeAssignment entity.
  • Kullanıcı bir Office atama değeri girerse ve başlangıçta boşsa, yeni bir OfficeAssignment varlığı oluşturmanız gerekir.If the user enters an office assignment value and it originally was empty, you must create a new OfficeAssignment entity.
  • Kullanıcı bir Office atamasının değerini değiştirirse, mevcut bir OfficeAssignment varlığındaki değeri değiştirmeniz gerekir.If the user changes the value of an office assignment, you must change the value in an existing OfficeAssignment entity.

InstructorController.cs ' i açın ve HttpGet Edit yöntemine bakın:Open InstructorController.cs and look at the HttpGet Edit method:

public ActionResult Edit(int id = 0)
{
    Instructor instructor = db.Instructors.Find(id);
    if (instructor == null)
    {
        return HttpNotFound();
    }
    ViewBag.InstructorID = new SelectList(db.OfficeAssignments, "InstructorID", "Location", instructor.InstructorID);
    return View(instructor);
}

Burada scafkatlama kodu istediğiniz gibi değildir.The scaffolded code here isn't what you want. Bu, bir açılan liste için veri ayarlıyor, ancak ihtiyacınız olan bir metin kutusu.It's setting up data for a drop-down list, but you what you need is a text box. Bu yöntemi aşağıdaki kodla değiştirin:Replace this method with the following code:

public ActionResult Edit(int id)
{
    Instructor instructor = db.Instructors
        .Include(i => i.OfficeAssignment)
        .Where(i => i.InstructorID == id)
        .Single();
    return View(instructor);
}

Bu kod ViewBag ifadesini bırakır ve ilişkili OfficeAssignment varlığı için ekip yükleme ekler.This code drops the ViewBag statement and adds eager loading for the associated OfficeAssignment entity. Find yöntemiyle Eager yüklemesi gerçekleştiremezsiniz, bu nedenle Where ve Single yöntemleri eğitmeni seçmek için kullanılır.You can't perform eager loading with the Find method, so the Where and Single methods are used instead to select the instructor.

HttpPost Edit yöntemini aşağıdaki kodla değiştirin.Replace the HttpPost Edit method with the following code. Office atama güncelleştirmelerini işleyen:which handles office assignment updates:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int id, FormCollection formCollection)
{
   var instructorToUpdate = db.Instructors
       .Include(i => i.OfficeAssignment)
       .Where(i => i.InstructorID == id)
       .Single();

   if (TryUpdateModel(instructorToUpdate, "",
      new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
   {
      try
      {
         if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location))
         {
            instructorToUpdate.OfficeAssignment = null;
         }

         db.Entry(instructorToUpdate).State = EntityState.Modified;
         db.SaveChanges();

         return RedirectToAction("Index");
      }
      catch (DataException /* dex */)
      {
         //Log the error (uncomment dex variable name after DataException and add a line here to write a log.
         ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
      }
   }
   ViewBag.InstructorID = new SelectList(db.OfficeAssignments, "InstructorID", "Location", id);
   return View(instructorToUpdate);
}

Kod şunları yapar:The code does the following:

  • OfficeAssignment gezinti özelliği için Eager yükleme kullanarak geçerli Instructor varlığını veritabanından alır.Gets the current Instructor entity from the database using eager loading for the OfficeAssignment navigation property. Bu, HttpGet Edit yönteminde yaptığınız şeydir.This is the same as what you did in the HttpGet Edit method.

  • Alınan Instructor varlığını model Ciltçideki değerlerle güncelleştirir.Updates the retrieved Instructor entity with values from the model binder. Kullanılan TryUpdateModel aşırı yüklemesi, dahil etmek istediğiniz özellikleri beyaz listelemenize olanak sağlar.The TryUpdateModel overload used enables you to whitelist the properties you want to include. Bu, ikinci öğreticideaçıklandığı gibi, daha fazla nakletmeyi önler.This prevents over-posting, as explained in the second tutorial.

    if (TryUpdateModel(instructorToUpdate, "",
          new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
    
  • Office konumu boşsa, OfficeAssignment tablosundaki ilgili satırın silinebilmesi için Instructor.OfficeAssignment özelliğini null olarak ayarlar.If the office location is blank, sets the Instructor.OfficeAssignment property to null so that the related row in the OfficeAssignment table will be deleted.

    if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location))
    {
        instructorToUpdate.OfficeAssignment = null;
    }
    
  • Değişiklikleri veritabanına kaydeder.Saves the changes to the database.

Views\komutctor\edit.exe' de, işe alma tarihi alanı için div öğelerinden sonra, Office konumunu düzenlemekte yeni bir alan ekleyin:In Views\Instructor\Edit.cshtml, after the div elements for the Hire Date field, add a new field for editing the office location:

<div class="editor-label">
    @Html.LabelFor(model => model.OfficeAssignment.Location)
</div>
<div class="editor-field">
    @Html.EditorFor(model => model.OfficeAssignment.Location)
    @Html.ValidationMessageFor(model => model.OfficeAssignment.Location)
</div>

Sayfayı çalıştırın ( eğitmenler sekmesini seçin ve ardından bir eğitmende Düzenle ' ye tıklayın).Run the page (select the Instructors tab and then click Edit on an instructor). Office konumunu değiştirin ve Kaydet' e tıklayın.Change the Office Location and click Save.

Changing_the_office_location

Eğitmen düzenleme sayfasına kurs atamaları eklemeAdding Course Assignments to the Instructor Edit Page

Eğitmenler, istediğiniz sayıda kurs öğretebilir.Instructors may teach any number of courses. Artık, aşağıdaki ekran görüntüsünde gösterildiği gibi, bir grup onay kutusu kullanarak kurs atamalarını değiştirme özelliğini ekleyerek eğitmen düzenleme sayfasını geliştirirsiniz:Now you'll enhance the Instructor Edit page by adding the ability to change course assignments using a group of check boxes, as shown in the following screen shot:

Instructor_edit_page_with_courses

Course ve Instructor varlıkları arasındaki ilişki çoktan çoğa, bu, JOIN tablosuna doğrudan erişiminizin olmadığı anlamına gelir.The relationship between the Course and Instructor entities is many-to-many, which means you do not have direct access to the join table. Bunun yerine, Instructor.Courses gezinti özelliğine ve öğesinden varlık ekleyip kaldıracaksınız.Instead, you will add and remove entities to and from the Instructor.Courses navigation property.

Bir eğitmenin hangi kurslara atandığını değiştirmenize olanak sağlayan kullanıcı arabirimi bir grup onay kutusu olur.The UI that enables you to change which courses an instructor is assigned to is a group of check boxes. Veritabanındaki her kurs için bir onay kutusu görüntülenir ve eğitmenin Şu anda atanmış olduğu yer seçilidir.A check box for every course in the database is displayed, and the ones that the instructor is currently assigned to are selected. Kullanıcı kurs atamalarını değiştirmek için onay kutularını seçebilir veya temizleyebilir.The user can select or clear check boxes to change course assignments. Kurs sayısı çok fazlaysa, büyük olasılıkla görünümde verileri göstermek için farklı bir yöntem kullanmak isteyeceksiniz, ancak ilişkiler oluşturmak veya silmek için gezinti özelliklerini düzenleme yöntemini kullanırsınız.If the number of courses were much greater, you would probably want to use a different method of presenting the data in the view, but you'd use the same method of manipulating navigation properties in order to create or delete relationships.

Onay kutuları listesinin görünümüne veri sağlamak için bir görünüm modeli sınıfı kullanacaksınız.To provide data to the view for the list of check boxes, you'll use a view model class. Viewmodeller klasöründe AssignedCourseData.cs oluşturun ve mevcut kodu şu kodla değiştirin:Create AssignedCourseData.cs in the ViewModels folder and replace the existing code with the following code:

namespace ContosoUniversity.ViewModels
{
    public class AssignedCourseData
    {
        public int CourseID { get; set; }
        public string Title { get; set; }
        public bool Assigned { get; set; }
    }
}

InstructorController.cs' de HttpGet Edit yöntemini aşağıdaki kodla değiştirin.In InstructorController.cs, replace the HttpGet Edit method with the following code. Değişiklikler vurgulanır.The changes are highlighted.

public ActionResult Edit(int id)
{
    Instructor instructor = db.Instructors
        .Include(i => i.OfficeAssignment)
        .Include(i => i.Courses)
        .Where(i => i.InstructorID == id)
        .Single();
    PopulateAssignedCourseData(instructor);
    return View(instructor);
}

private void PopulateAssignedCourseData(Instructor instructor)
{
    var allCourses = db.Courses;
    var instructorCourses = new HashSet<int>(instructor.Courses.Select(c => c.CourseID));
    var viewModel = new List<AssignedCourseData>();
    foreach (var course in allCourses)
    {
        viewModel.Add(new AssignedCourseData
        {
            CourseID = course.CourseID,
            Title = course.Title,
            Assigned = instructorCourses.Contains(course.CourseID)
        });
    }
    ViewBag.Courses = viewModel;
}

Kod, Courses gezinti özelliği için Eager yüklemesi ekler ve AssignedCourseData View model sınıfını kullanarak onay kutusu dizisi bilgilerini sağlamak için yeni PopulateAssignedCourseData yöntemini çağırır.The code adds eager loading for the Courses navigation property and calls the new PopulateAssignedCourseData method to provide information for the check box array using the AssignedCourseData view model class.

PopulateAssignedCourseData yöntemindeki kod, görünüm modeli sınıfını kullanarak bir kurs listesi yüklemek için tüm Course varlıklarından okur.The code in the PopulateAssignedCourseData method reads through all Course entities in order to load a list of courses using the view model class. Kod, her kurs için, kursun Courses gezinti özelliğinde mevcut olup olmadığını denetler.For each course, the code checks whether the course exists in the instructor's Courses navigation property. Eğitmenin bir kurs atanıp atanmadığını denetlerken etkili arama oluşturmak için, eğitmene atanan kurslar bir diyez kümesi koleksiyonuna konur.To create efficient lookup when checking whether a course is assigned to the instructor, the courses assigned to the instructor are put into a HashSet collection. Assigned özelliği, eğitmenin atandığı kurslar için true olarak ayarlanır.The Assigned property is set to true for courses the instructor is assigned. Görünüm, hangi onay kutularının seçili olarak gösterileceğini belirlemede bu özelliği kullanır.The view will use this property to determine which check boxes must be displayed as selected. Son olarak, liste bir ViewBag özelliğindeki görünüme geçirilir.Finally, the list is passed to the view in a ViewBag property.

Sonra, Kullanıcı Kaydet' i tıklattığında yürütülen kodu ekleyin.Next, add the code that's executed when the user clicks Save. HttpPost Edit yöntemini, Instructor varlığının Courses gezinti özelliğini güncelleştiren yeni bir yöntemi çağıran aşağıdaki kodla değiştirin.Replace the HttpPost Edit method with the following code, which calls a new method that updates the Courses navigation property of the Instructor entity. Değişiklikler vurgulanır.The changes are highlighted.

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int id, FormCollection formCollection, string[] selectedCourses)
{
   var instructorToUpdate = db.Instructors
       .Include(i => i.OfficeAssignment)
       .Include(i => i.Courses)
       .Where(i => i.InstructorID == id)
       .Single();
   if (TryUpdateModel(instructorToUpdate, "", 
      new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
   {
      try
      {
         if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location))
         {
            instructorToUpdate.OfficeAssignment = null;
         }

         UpdateInstructorCourses(selectedCourses, instructorToUpdate);

         db.Entry(instructorToUpdate).State = EntityState.Modified;
         db.SaveChanges();

         return RedirectToAction("Index");
      }
      catch (DataException /* dex */)
      {
         //Log the error (uncomment dex variable name after DataException and add a line here to write a log.
         ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
      }
   }
   PopulateAssignedCourseData(instructorToUpdate);
   return View(instructorToUpdate);
}

private void UpdateInstructorCourses(string[] selectedCourses, Instructor instructorToUpdate)
{
   if (selectedCourses == null)
   {
      instructorToUpdate.Courses = new List<Course>();
      return;
   }

   var selectedCoursesHS = new HashSet<string>(selectedCourses);
   var instructorCourses = new HashSet<int>
       (instructorToUpdate.Courses.Select(c => c.CourseID));
   foreach (var course in db.Courses)
   {
      if (selectedCoursesHS.Contains(course.CourseID.ToString()))
      {
         if (!instructorCourses.Contains(course.CourseID))
         {
            instructorToUpdate.Courses.Add(course);
         }
      }
      else
      {
         if (instructorCourses.Contains(course.CourseID))
         {
            instructorToUpdate.Courses.Remove(course);
         }
      }
   }
}

Görünümün bir Course varlıkları koleksiyonu olmadığından, model Bağlayıcısı Courses gezinti özelliğini otomatik olarak güncelleştiremez.Since the view doesn't have a collection of Course entities, the model binder can't automatically update the Courses navigation property. Kurs gezintisi özelliğini güncelleştirmek için model cildi kullanmak yerine, bunu yeni UpdateInstructorCourses yönteminde yapmanız gerekir.Instead of using the model binder to update the Courses navigation property, you'll do that in the new UpdateInstructorCourses method. Bu nedenle Courses özelliğini model bağlamadan çıkarmanız gerekir.Therefore you need to exclude the Courses property from model binding. Bu, beyaz liste aşırı yüklemesini kullandığınız ve Courses içerme listesinde olmadığı Için TryUpdateModel 'i çağıran kodda herhangi bir değişiklik yapılmasını gerektirmez.This doesn't require any change to the code that calls TryUpdateModel because you're using the whitelisting overload and Courses isn't in the include list.

Hiçbir onay kutusu seçilmediyse UpdateInstructorCourses kod, Courses gezinti özelliğini boş bir koleksiyon ile başlatır:If no check boxes were selected, the code in UpdateInstructorCourses initializes the Courses navigation property with an empty collection:

if (selectedCourses == null)
{
    instructorToUpdate.Courses = new List<Course>();
    return;
}

Kod daha sonra, veritabanındaki tüm kurslardan geçer ve bu her kursu, görünümde seçili olanlar ile ilgili olarak eğitmenin atandığı her bir kursa karşı denetler.The code then loops through all courses in the database and checks each course against the ones currently assigned to the instructor versus the ones that were selected in the view. Etkili aramaları kolaylaştırmak için, ikinci iki koleksiyon HashSet nesnelerinde depolanır.To facilitate efficient lookups, the latter two collections are stored in HashSet objects.

Kurs onay kutusu seçilmişse ancak kurs Instructor.Courses gezinti özelliğinde değilse, kurs, Gezinti özelliğindeki koleksiyona eklenir.If the check box for a course was selected but the course isn't in the Instructor.Courses navigation property, the course is added to the collection in the navigation property.

if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
    if (!instructorCourses.Contains(course.CourseID))
    {
        instructorToUpdate.Courses.Add(course);
    }
}

Kurs onay kutusu seçilmemişse, ancak kurs Instructor.Courses gezinti özelliği ise, kurs, gezinti özelliğinden kaldırılır.If the check box for a course wasn't selected, but the course is in the Instructor.Courses navigation property, the course is removed from the navigation property.

else
{
    if (instructorCourses.Contains(course.CourseID))
    {
        instructorToUpdate.Courses.Remove(course);
    }
}

Views\komutctor\edit.exe' de, OfficeAssignment alanı için div öğelerinden hemen sonra aşağıdaki vurgulanmış kodu ekleyerek bir dizi onay kutusu Içeren bir Kurslar alanı ekleyin:In Views\Instructor\Edit.cshtml, add a Courses field with an array of check boxes by adding the following highlighted code immediately after the div elements for the OfficeAssignment field:

@model ContosoUniversity.Models.Instructor

@{
    ViewBag.Title = "Edit";
}

<h2>Edit</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Instructor</legend>

        @Html.HiddenFor(model => model.InstructorID)

        <div class="editor-label">
            @Html.LabelFor(model => model.LastName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.LastName)
            @Html.ValidationMessageFor(model => model.LastName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.FirstMidName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.FirstMidName)
            @Html.ValidationMessageFor(model => model.FirstMidName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.HireDate)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.HireDate)
            @Html.ValidationMessageFor(model => model.HireDate)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.OfficeAssignment.Location)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.OfficeAssignment.Location)
            @Html.ValidationMessageFor(model => model.OfficeAssignment.Location)
        </div>

        <div class="editor-field">
    <table>
        <tr>
            @{
                int cnt = 0;
                List<ContosoUniversity.ViewModels.AssignedCourseData> courses = ViewBag.Courses;

                foreach (var course in courses) {
                    if (cnt++ % 3 == 0) {
                        @:  </tr> <tr> 
                    }
                    @: <td> 
                        <input type="checkbox" 
                               name="selectedCourses" 
                               value="@course.CourseID" 
                               @(Html.Raw(course.Assigned ? "checked=\"checked\"" : "")) /> 
                        @course.CourseID @:  @course.Title
                    @:</td>
                }
                @: </tr>
            }
    </table>
</div>
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Bu kod, üç sütun içeren bir HTML tablosu oluşturur.This code creates an HTML table that has three columns. Her sütunda, bir onay kutusu ve ardından kurs numarası ve başlığından oluşan bir açıklamalı alt yazı bulunur.In each column is a check box followed by a caption that consists of the course number and title. Onay kutularının hepsi aynı ada ("Selectedkurslar") sahiptir, bu da model cilde bir grup olarak değerlendirilme bildirir.The check boxes all have the same name ("selectedCourses"), which informs the model binder that they are to be treated as a group. Her onay kutusunun value özniteliği, sayfa gönderildiğinde CourseID. değerine ayarlanır, model Ciltçi yalnızca seçili onay kutularının CourseID değerlerinden oluşan bir diziyi denetleyiciye geçirir.The value attribute of each check box is set to the value of CourseID. When the page is posted, the model binder passes an array to the controller that consists of the CourseID values for only the check boxes which are selected.

Onay kutuları başlangıçta işlendiğinde, eğitmenin atandığı kurslara yönelik olanlar, onları seçen checked özniteliklerine sahiptir (bunları işaretli olarak görüntüler).When the check boxes are initially rendered, those that are for courses assigned to the instructor have checked attributes, which selects them (displays them checked).

Kurs atamalarını değiştirdikten sonra, site Index sayfasına döndüğünde değişiklikleri doğrulayabilmek isteyeceksiniz.After changing course assignments, you'll want to be able to verify the changes when the site returns to the Index page. Bu nedenle, bu sayfadaki tabloya bir sütun eklemeniz gerekir.Therefore, you need to add a column to the table in that page. Bu durumda, göstermek istediğiniz bilgiler, sayfaya model olarak geçirdiğiniz Instructor varlığının Courses gezinti özelliğinde zaten yer aldığı için ViewBag nesnesini kullanmanız gerekmez.In this case you don't need to use the ViewBag object, because the information you want to display is already in the Courses navigation property of the Instructor entity that you're passing to the page as the model.

Views\komutctor\ındex.cshtmliçinde, aşağıdaki örnekte gösterildiği gibi, Office başlığından hemen sonra bir Kurslar başlığı ekleyin:In Views\Instructor\Index.cshtml, add a Courses heading immediately following the Office heading, as shown in the following example:

<tr> 
    <th></th> 
    <th>Last Name</th> 
    <th>First Name</th> 
    <th>Hire Date</th> 
    <th>Office</th>
    <th>Courses</th>
</tr>

Ardından, Office konumu ayrıntı hücresini hemen takip eden yeni bir ayrıntı hücresi ekleyin:Then add a new detail cell immediately following the office location detail cell:

@model ContosoUniversity.ViewModels.InstructorIndexData

@{
    ViewBag.Title = "Instructors";
}

<h2>Instructors</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table>
    <tr>
        <th></th>
        <th>Last Name</th>
        <th>First Name</th>
        <th>Hire Date</th>
        <th>Office</th>
        <th>Courses</th>
    </tr>
    @foreach (var item in Model.Instructors)
    {
        string selectedRow = "";
        if (item.InstructorID == ViewBag.InstructorID)
        {
            selectedRow = "selectedrow";
        } 
        <tr class="@selectedRow" valign="top">
            <td>
                @Html.ActionLink("Select", "Index", new { id = item.InstructorID }) | 
                @Html.ActionLink("Edit", "Edit", new { id = item.InstructorID }) | 
                @Html.ActionLink("Details", "Details", new { id = item.InstructorID }) | 
                @Html.ActionLink("Delete", "Delete", new { id = item.InstructorID })
            </td>
            <td>
                @item.LastName
            </td>
            <td>
                @item.FirstMidName
            </td>
            <td>
                @String.Format("{0:d}", item.HireDate)
            </td>
            <td>
                @if (item.OfficeAssignment != null)
                { 
                    @item.OfficeAssignment.Location  
                }
            </td>
            <td>
                @{
                foreach (var course in item.Courses)
                {
                    @course.CourseID @:  @course.Title <br />
                }
                }
            </td>
        </tr> 
    }
</table>

@if (Model.Courses != null)
{ 
    <h3>Courses Taught by Selected Instructor</h3> 
    <table>
        <tr>
            <th></th>
            <th>ID</th>
            <th>Title</th>
            <th>Department</th>
        </tr>

        @foreach (var item in Model.Courses)
        {
            string selectedRow = "";
            if (item.CourseID == ViewBag.CourseID)
            {
                selectedRow = "selectedrow";
            } 
        
            <tr class="@selectedRow">

                <td>
                    @Html.ActionLink("Select", "Index", new { courseID = item.CourseID })
                </td>
                <td>
                    @item.CourseID
                </td>
                <td>
                    @item.Title
                </td>
                <td>
                    @item.Department.Name
                </td>
            </tr> 
        }

    </table> 
}
@if (Model.Enrollments != null)
{ 
    <h3>Students Enrolled in Selected Course</h3> 
    <table>
        <tr>
            <th>Name</th>
            <th>Grade</th>
        </tr>
        @foreach (var item in Model.Enrollments)
        { 
            <tr>
                <td>
                    @item.Student.FullName
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Grade)
                </td>
            </tr> 
        }
    </table> 
}

Her bir eğitmene atanan kursları görmek için eğitmen dizini sayfasını çalıştırın:Run the Instructor Index page to see the courses assigned to each instructor:

Instructor_index_page

Düzenleme sayfasını görmek için bir eğitmende Düzenle ' ye tıklayın.Click Edit on an instructor to see the Edit page.

Instructor_edit_page_with_courses

Bazı kurs atamalarını değiştirin ve Kaydet' e tıklayın.Change some course assignments and click Save. Yaptığınız değişiklikler Dizin sayfasında yansıtılır.The changes you make are reflected on the Index page.

Note: Eğitmen Kursu verilerini düzenlemek için uygulanan yaklaşım, sınırlı sayıda kurs olduğunda iyi sonuç verir.Note: The approach taken to edit instructor course data works well when there is a limited number of courses. Çok daha büyük olan koleksiyonlar için, farklı bir kullanıcı arabirimi ve farklı bir güncelleştirme yöntemi gerekir.For collections that are much larger, a different UI and a different updating method would be required.

Delete metodunu GüncelleştirUpdate the Delete Method

Http atama kaydının (varsa) eğitmen silindiğinde silinmesi için HttpPost silme yöntemindeki kodu değiştirin:Change the code in the HttpPost Delete method so the office assignment record (if any) is deleted when the instructor is deleted:

[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
   Instructor instructor = db.Instructors
     .Include(i => i.OfficeAssignment)
     .Where(i => i.InstructorID == id)
     .Single();

   instructor.OfficeAssignment = null;
   db.Instructors.Remove(instructor);
   db.SaveChanges();
   return RedirectToAction("Index");
}

Bir departmana yönetici olarak atanmış bir eğitmeni silmeye çalışırsanız, bir başvuru bütünlüğü hatası alırsınız.If you try to delete an instructor who is assigned to a department as administrator, you'll get a referential integrity error. Eğitmeni bir yönetici olarak atanan herhangi bir departmandan otomatik olarak kaldıracak olan ek kod için Bu öğreticinin güncel sürümüne bakın.See the current version of this tutorial for additional code that will automatically remove the instructor from any department where the instructor is assigned as an administrator.

ÖzetSummary

Artık ilgili verilerle çalışmaya yönelik bu girişi tamamladınız.You have now completed this introduction to working with related data. Bu öğreticilerde, çok sayıda CRUD işlemi yaptık, ancak eşzamanlılık sorunlarıyla karşılaşmadınız.So far in these tutorials you've done a full range of CRUD operations, but you haven't dealt with concurrency issues. Sonraki öğreticide eşzamanlılık, işleme için açıklama seçenekleri ve bir varlık türü için zaten yazdığınız CRUD koduna eşzamanlılık işleme ekleme konusu ele alınacaktır.The next tutorial will introduce the topic of concurrency, explain options for handling it, and add concurrency handling to the CRUD code you've already written for one entity type.

Diğer Entity Framework kaynaklarına bağlantılar, Bu serideki son öğreticininsonunda bulunabilir.Links to other Entity Framework resources, can be found at the end of the last tutorial in this series.