Wprowadzenie z programem Entity Framework 4.0 Database First i ASP.NET 4 Web Forms — część 5
Autor : Tom Dykstra
Przykładowa aplikacja internetowa Contoso University pokazuje, jak tworzyć aplikacje ASP.NET Web Forms przy użyciu platform Entity Framework 4.0 i Visual Studio 2010. Aby uzyskać informacje na temat serii samouczków, zobacz pierwszy samouczek z serii
Praca z powiązanymi danymi, kontynuowanie
W poprzednim samouczku rozpoczęto korzystanie z kontrolki EntityDataSource
do pracy z powiązanymi danymi. W właściwościach nawigacji wyświetlane są wiele poziomów hierarchii i edytowane dane. W tym samouczku będziesz nadal pracować z powiązanymi danymi, dodając i usuwając relacje oraz dodając nową jednostkę, która ma relację z istniejącą jednostką.
Utworzysz stronę, która dodaje kursy przypisane do działów. Działy już istnieją i podczas tworzenia nowego kursu ustanowisz relację między nim i istniejącym działem.
Utworzysz również stronę, która współpracuje z relacją wiele-do-wielu, przypisując instruktora do kursu (dodając relację między dwoma wybranymi jednostkami) lub usuwając instruktora z kursu (usuwając relację między dwoma wybranymi jednostkami). W bazie danych dodanie relacji między instruktorem a kursem powoduje dodanie nowego wiersza do CourseInstructor
tabeli skojarzeń. Usunięcie relacji obejmuje usunięcie wiersza z CourseInstructor
tabeli skojarzeń. Można to jednak zrobić w programie Entity Framework, ustawiając właściwości nawigacji bez jawnego CourseInstructor
odwoływania się do tabeli.
Dodawanie jednostki z relacją do istniejącej jednostki
Utwórz nową stronę internetową o nazwie CoursesAdd.aspx korzystającą ze strony wzorcowej Site.Master i dodaj następujący znacznik do kontrolki Content
o nazwie Content2
:
<h2>Add Courses</h2>
<asp:EntityDataSource ID="CoursesEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
EntitySetName="Courses"
EnableInsert="True" EnableDelete="True" >
</asp:EntityDataSource>
<asp:DetailsView ID="CoursesDetailsView" runat="server" AutoGenerateRows="False"
DataSourceID="CoursesEntityDataSource" DataKeyNames="CourseID"
DefaultMode="Insert" oniteminserting="CoursesDetailsView_ItemInserting">
<Fields>
<asp:BoundField DataField="CourseID" HeaderText="ID" />
<asp:BoundField DataField="Title" HeaderText="Title" />
<asp:BoundField DataField="Credits" HeaderText="Credits" />
<asp:TemplateField HeaderText="Department">
<InsertItemTemplate>
<asp:EntityDataSource ID="DepartmentsEntityDataSource" runat="server" ConnectionString="name=SchoolEntities"
DefaultContainerName="SchoolEntities" EnableDelete="True" EnableFlattening="False"
EntitySetName="Departments" EntityTypeFilter="Department">
</asp:EntityDataSource>
<asp:DropDownList ID="DepartmentsDropDownList" runat="server" DataSourceID="DepartmentsEntityDataSource"
DataTextField="Name" DataValueField="DepartmentID"
oninit="DepartmentsDropDownList_Init">
</asp:DropDownList>
</InsertItemTemplate>
</asp:TemplateField>
<asp:CommandField ShowInsertButton="True" />
</Fields>
</asp:DetailsView>
Ten znacznik tworzy kontrolkę EntityDataSource
, która wybiera kursy, która umożliwia wstawianie i określa procedurę obsługi dla zdarzenia Inserting
. Użyjesz procedury obsługi, aby zaktualizować właściwość nawigacji po utworzeniu Department
nowej Course
jednostki.
Znacznik tworzy również kontrolkę służącą DetailsView
do dodawania nowych Course
jednostek. Znacznik używa pól powiązanych dla Course
właściwości jednostki. Musisz wprowadzić CourseID
wartość, ponieważ nie jest to pole identyfikatora generowanego przez system. Zamiast tego jest to numer kursu, który należy określić ręcznie podczas tworzenia kursu.
Dla właściwości nawigacji jest używane pole Department
szablonu, ponieważ nie można używać właściwości nawigacji z kontrolkami BoundField
. Pole szablonu zawiera listę rozwijaną do wybrania działu. Lista rozwijana jest powiązana z zestawem Departments
jednostek za pomocą polecenia Eval
, a nie Bind
, ponieważ nie można bezpośrednio powiązać właściwości nawigacji w celu ich zaktualizowania. Należy określić procedurę obsługi dla DropDownList
zdarzenia kontrolki Init
, aby można było przechowywać odwołanie do kontrolki do użycia przez kod aktualizujący DepartmentID
klucz obcy.
W pliku CoursesAdd.aspx.cs tuż po deklaracji częściowej klasy dodaj pole klasy do przechowywania odwołania do kontrolki DepartmentsDropDownList
:
private DropDownList departmentDropDownList;
Dodaj procedurę obsługi dla DepartmentsDropDownList
zdarzenia kontrolki Init
, aby można było przechowywać odwołanie do kontrolki. Dzięki temu można uzyskać wartość wprowadzoną przez użytkownika i użyć jej do zaktualizowania DepartmentID
wartości Course
jednostki.
protected void DepartmentsDropDownList_Init(object sender, EventArgs e)
{
departmentDropDownList = sender as DropDownList;
}
Dodaj procedurę obsługi dla DetailsView
zdarzenia kontrolki Inserting
:
protected void CoursesDetailsView_ItemInserting(object sender, DetailsViewInsertEventArgs e)
{
var departmentID = Convert.ToInt32(departmentDropDownList.SelectedValue);
e.Values["DepartmentID"] = departmentID;
}
Gdy użytkownik kliknie Insert
przycisk , Inserting
zdarzenie zostanie zgłoszone przed wstawionym nowym rekordem. Kod w procedurze obsługi pobiera element DepartmentID
z kontrolki DropDownList
i używa go do ustawienia wartości, która będzie używana dla DepartmentID
właściwości Course
jednostki.
Program Entity Framework zajmie się dodaniem tego kursu do Courses
właściwości nawigacji skojarzonej Department
jednostki. Dodaje również dział do Department
właściwości Course
nawigacji jednostki.
Uruchom stronę.
Wprowadź identyfikator, tytuł, liczbę środków i wybierz dział, a następnie kliknij pozycję Wstaw.
Uruchom stronę Courses.aspx i wybierz ten sam dział, aby zobaczyć nowy kurs.
Praca z relacjami wiele-do-wielu
Relacja między zestawem Courses
jednostek a People
zestawem jednostek jest relacją wiele do wielu. Jednostka Course
ma właściwość nawigacji o nazwie People
, która może zawierać zero, co najmniej jedną powiązaną Person
jednostkę (reprezentując instruktorów przypisanych do nauczania tego kursu). Person
Jednostka ma właściwość nawigacji o nazwie Courses
, która może zawierać zero, co najmniej jedną powiązaną Course
jednostkę (reprezentując kursy przypisane przez instruktora do nauczania). Jeden z instruktorów może uczyć się wielu kursów, a jeden kurs może być nauczany przez wielu instruktorów. W tej sekcji przewodnika dodasz i usuniesz relacje między jednostkami Person
i Course
, aktualizując właściwości nawigacji powiązanych jednostek.
Utwórz nową stronę internetową o nazwie InstructorsCourses.aspx korzystającą ze strony wzorcowej Site.Master i dodaj następujący znacznik do kontrolki Content
o nazwie Content2
:
<h2>Assign Instructors to Courses or Remove from Courses</h2>
<br />
<asp:EntityDataSource ID="InstructorsEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
EntitySetName="People"
Where="it.HireDate is not null" Select="it.LastName + ', ' + it.FirstMidName AS Name, it.PersonID">
</asp:EntityDataSource>
Select an Instructor:
<asp:DropDownList ID="InstructorsDropDownList" runat="server" DataSourceID="InstructorsEntityDataSource"
AutoPostBack="true" DataTextField="Name" DataValueField="PersonID"
OnSelectedIndexChanged="InstructorsDropDownList_SelectedIndexChanged"
OnDataBound="InstructorsDropDownList_DataBound">
</asp:DropDownList>
<h3>
Assign a Course</h3>
<br />
Select a Course:
<asp:DropDownList ID="UnassignedCoursesDropDownList" runat="server"
DataTextField="Title" DataValueField="CourseID">
</asp:DropDownList>
<br />
<asp:Button ID="AssignCourseButton" runat="server" Text="Assign" OnClick="AssignCourseButton_Click" />
<br />
<asp:Label ID="CourseAssignedLabel" runat="server" Visible="false" Text="Assignment successful"></asp:Label>
<br />
<h3>
Remove a Course</h3>
<br />
Select a Course:
<asp:DropDownList ID="AssignedCoursesDropDownList" runat="server"
DataTextField="title" DataValueField="courseiD">
</asp:DropDownList>
<br />
<asp:Button ID="RemoveCourseButton" runat="server" Text="Remove" OnClick="RemoveCourseButton_Click" />
<br />
<asp:Label ID="CourseRemovedLabel" runat="server" Visible="false" Text="Removal successful"></asp:Label>
Ten znacznik tworzy kontrolkę EntityDataSource
, która pobiera nazwę i PersonID
Person
jednostki dla instruktorów. Kontrolka DropDrownList
jest powiązana z kontrolką EntityDataSource
. Kontrolka DropDownList
określa procedurę obsługi zdarzenia DataBound
. Użyjesz tej procedury obsługi do powiązania dwóch list rozwijanych, które wyświetlają kursy.
Znacznik tworzy również następującą grupę kontrolek, które mają być używane do przypisywania kursu do wybranego instruktora:
- Kontrolka
DropDownList
wybierania kursu do przypisania. Ta kontrolka zostanie wypełniona kursami, które nie są obecnie przypisane do wybranego instruktora. - Kontrolka
Button
inicjowania przypisania. - Kontrolka
Label
wyświetla komunikat o błędzie, jeśli przypisanie nie powiedzie się.
Na koniec adiustacja tworzy również grupę kontrolek, które mają być używane do usuwania kursu z wybranego instruktora.
W pliku InstructorsCourses.aspx.cs dodaj instrukcję using:
using ContosoUniversity.DAL;
Dodaj metodę wypełniania dwóch list rozwijanych, które wyświetlają kursy:
private void PopulateDropDownLists()
{
using (var context = new SchoolEntities())
{
var allCourses = (from c in context.Courses
select c).ToList();
var instructorID = Convert.ToInt32(InstructorsDropDownList.SelectedValue);
var instructor = (from p in context.People.Include("Courses")
where p.PersonID == instructorID
select p).First();
var assignedCourses = instructor.Courses.ToList();
var unassignedCourses = allCourses.Except(assignedCourses.AsEnumerable()).ToList();
UnassignedCoursesDropDownList.DataSource = unassignedCourses;
UnassignedCoursesDropDownList.DataBind();
UnassignedCoursesDropDownList.Visible = true;
AssignedCoursesDropDownList.DataSource = assignedCourses;
AssignedCoursesDropDownList.DataBind();
AssignedCoursesDropDownList.Visible = true;
}
}
Ten kod pobiera wszystkie kursy z Courses
zestawu jednostek i pobiera kursy z Courses
właściwości Person
nawigacji jednostki dla wybranego instruktora. Następnie określa, które kursy są przypisane do tego instruktora i odpowiednio wypełnia listy rozwijane.
Dodaj procedurę obsługi dla Assign
zdarzenia przycisku Click
:
protected void AssignCourseButton_Click(object sender, EventArgs e)
{
using (var context = new SchoolEntities())
{
var instructorID = Convert.ToInt32(InstructorsDropDownList.SelectedValue);
var instructor = (from p in context.People
where p.PersonID == instructorID
select p).First();
var courseID = Convert.ToInt32(UnassignedCoursesDropDownList.SelectedValue);
var course = (from c in context.Courses
where c.CourseID == courseID
select c).First();
instructor.Courses.Add(course);
try
{
context.SaveChanges();
PopulateDropDownLists();
CourseAssignedLabel.Text = "Assignment successful.";
}
catch (Exception)
{
CourseAssignedLabel.Text = "Assignment unsuccessful.";
//Add code to log the error.
}
CourseAssignedLabel.Visible = true;
}
}
Ten kod pobiera Person
jednostkę dla wybranego instruktora, pobiera Course
jednostkę dla wybranego kursu i dodaje wybrany kurs do Courses
właściwości nawigacji jednostki instruktora Person
. Następnie zapisuje zmiany w bazie danych i ponownie wypełnia listy rozwijane, aby wyniki były widoczne natychmiast.
Dodaj procedurę obsługi dla Remove
zdarzenia przycisku Click
:
protected void RemoveCourseButton_Click(object sender, EventArgs e)
{
using (var context = new SchoolEntities())
{
var instructorID = Convert.ToInt32(InstructorsDropDownList.SelectedValue);
var instructor = (from p in context.People
where p.PersonID == instructorID
select p).First();
var courseID = Convert.ToInt32(AssignedCoursesDropDownList.SelectedValue);
var courses = instructor.Courses;
var courseToRemove = new Course();
foreach (Course c in courses)
{
if (c.CourseID == courseID)
{
courseToRemove = c;
break;
}
}
try
{
courses.Remove(courseToRemove);
context.SaveChanges();
PopulateDropDownLists();
CourseRemovedLabel.Text = "Removal successful.";
}
catch (Exception)
{
CourseRemovedLabel.Text = "Removal unsuccessful.";
//Add code to log the error.
}
CourseRemovedLabel.Visible = true;
}
}
Ten kod pobiera Person
jednostkę dla wybranego instruktora, pobiera Course
jednostkę dla wybranego kursu i usuwa wybrany kurs z Person
właściwości nawigacji jednostki Courses
. Następnie zapisuje zmiany w bazie danych i ponownie wypełnia listy rozwijane, aby wyniki były widoczne natychmiast.
Dodaj kod do Page_Load
metody, która zapewnia, że komunikaty o błędach nie są widoczne, gdy nie ma żadnego błędu do raportowania, i dodaj programy obsługi dla DataBound
listy rozwijanej i SelectedIndexChanged
zdarzeń instruktorów, aby wypełnić listy rozwijane kursów:
protected void Page_Load(object sender, EventArgs e)
{
CourseAssignedLabel.Visible = false;
CourseRemovedLabel.Visible = false;
}
protected void InstructorsDropDownList_DataBound(object sender, EventArgs e)
{
PopulateDropDownLists();
}
protected void InstructorsDropDownList_SelectedIndexChanged(object sender, EventArgs e)
{
PopulateDropDownLists();
}
Uruchom stronę.
Wybierz instruktora. Lista rozwijana Przypisz kurs zawiera kursy, których instruktor nie uczy, a lista rozwijana Usuń kurs zawiera kursy, do których jest już przypisany instruktor. W sekcji Przypisywanie kursu wybierz kurs, a następnie kliknij pozycję Przypisz. Kurs przechodzi do listy rozwijanej Usuń kurs . Wybierz kurs w sekcji Usuń kurs , a następnie kliknij przycisk Usuń. Kurs zostanie przeniesiony do listy rozwijanej Przypisz kurs .
Znasz już kilka sposobów pracy z powiązanymi danymi. W poniższym samouczku dowiesz się, jak używać dziedziczenia w modelu danych, aby zwiększyć łatwość konserwacji aplikacji.