Работа с внешними ключами (платформа Entity Framework)
Начиная с .NET Framework версии 4, можно предоставить доступ к свойствам внешнего ключа типов сущности и определить отношения через внешние ключи. По умолчанию в мастере модель EDM (сущностная модель данных) установлен параметр Включить столбцы внешнего ключа в модель. Если этот параметр выбран, то формируемые объекты сущности имеют скалярные свойства, сопоставленные со столбцами внешнего ключа.
Свойства внешних ключей позволяют создавать и изменять отношение без обращения к основному объекту. При включении свойств внешнего ключа можно также изменить отношение путем обновления ссылки на основной объект в зависимом либо добавив зависимый объект в набор основных объектов. Доступ к ссылкам и наборам сущностей производится через свойства навигации. Дополнительные сведения см. в разделе Свойства навигации.
Entity Framework пытается обеспечить синхронизацию свойств ссылок, коллекций и внешних ключей. При обновлении свойства внешнего ключа зависимого объекта ссылка на этот объект и коллекция основного объекта должны быть синхронизированы. Для синхронизации сущности должны быть присоединены к контексту объекта и должны отслеживаться Entity Framework . Дополнительные сведения см. в разделах Разрешение идентификаторов, управление состоянием и отслеживание изменений (платформа Entity Framework) и Определение отношений и управление отношениями (платформа Entity Framework).
Примеры в этом разделе основаны на модели School, модель. Тип сущностей в этих примерах созданы средствами модель EDM (сущностная модель данных) . Созданные типы отслеживаются платформой Entity Framework. Дополнительные сведения о типах POCO см. в разделе Отслеживание изменений в сущностях POCO (платформа Entity Framework).
В следующем примере показано изменение отношения между двумя существующими объектами.
Dim studentId As Integer = 6
Dim enrollmentID As Integer = 2
Using context = New SchoolEntities()
' Get StudentGrade.
Dim grade = (From g In context.StudentGrades
Where g.EnrollmentID = enrollmentID
Select g).First()
' Change the relationship.
grade.StudentID = studentId
' You can access Person reference object on the grade object
' without loading the reference explicitly when
' the lazy loading option is set to true.
Console.WriteLine(grade.Person.PersonID)
' Save the changes.
context.SaveChanges()
End Using
int studentId = 6;
int enrollmentID = 2;
using (var context = new SchoolEntities())
{
// Get StudentGrade.
var grade = (from g in context.StudentGrades
where g.EnrollmentID == enrollmentID
select g).First();
// Change the relationship.
grade.StudentID = studentId;
// You can access Person reference object on the grade object
// without loading the reference explicitly when
// the lazy loading option is set to true.
Console.WriteLine(grade.Person.PersonID);
// Save the changes.
context.SaveChanges();
}
Следующий пример показывает, как установить отношение между новым зависимым объектом и существующими основными объектами через задание свойств внешнего ключа.
' The following example creates a new StudentGrade object and associates
' the StudentGrade with the Course and Person by
' setting the foreign key properties.
Using context As New SchoolEntities()
' The database will generate the EnrollmentID.
' To create the association between the Course and StudentGrade,
' and the Student and the StudentGrade, set the foreign key property
' to the ID of the principal.
Dim newStudentGrade = New StudentGrade With
{
.EnrollmentID = 0,
.Grade = CDec(4.0),
.CourseID = 4022,
.StudentID = 17
}
' Adding the new object to the context will synchronize
' the references with the foreign keys on the newStudentGrade object.
context.StudentGrades.AddObject(newStudentGrade)
' You can access Course and Student objects on the newStudentGrade object
' without loading the references explicitly because
' the lazy loading option is set to true in the constructor of SchoolEntities.
Console.WriteLine("Student ID {0}:", newStudentGrade.Person.PersonID)
Console.WriteLine("Course ID {0}:", newStudentGrade.Course.CourseID)
context.SaveChanges()
End Using
// The following example creates a new StudentGrade object and associates
// the StudentGrade with the Course and Person by
// setting the foreign key properties.
using (SchoolEntities context = new SchoolEntities())
{
StudentGrade newStudentGrade = new StudentGrade
{
// The database will generate the EnrollmentID.
EnrollmentID = 0,
Grade = 4.0M,
// To create the association between the Course and StudentGrade,
// and the Student and the StudentGrade, set the foreign key property
// to the ID of the principal.
CourseID = 4022,
StudentID = 17,
};
// Adding the new object to the context will synchronize
// the references with the foreign keys on the newStudentGrade object.
context.StudentGrades.AddObject(newStudentGrade);
// You can access Course and Student objects on the newStudentGrade object
// without loading the references explicitly because
// the lazy loading option is set to true in the constructor of SchoolEntities.
Console.WriteLine("Student ID {0}:", newStudentGrade.Person.PersonID);
Console.WriteLine("Course ID {0}:", newStudentGrade.Course.CourseID);
context.SaveChanges();
}
В следующем примере показано, как установить отношение между новым зависимым объектом и новым основным объектом.
Using context = New SchoolEntities()
' The database will generate PersonID.
' The object context will get the ID
' After the SaveChanges is called.
Dim newStudent = New Person With
{
.PersonID = 0,
.LastName = "Li",
.FirstName = "Yan"
}
' The database will generate EnrollmentID.
' The object context will get the ID
' After the SaveChanges is called.
Dim newStudentGrade = New StudentGrade With
{
.EnrollmentID = 0,
.Grade = CDec(4.0),
.StudentID = 50
}
' Add newStudent to object context.
' The newStudent's state will change from Detached to Added.
context.People.AddObject(newStudent)
' To associate the new objects you can do one of the following:
' Add the new dependent object to the principal object: newStudent.StudentGrades.Add(newStudentGrade).
' Assign the reference (principal) object to the navigation property of the
' dependent object: newStudentGrade.Person = newStudent.
' Both of these methods will synchronize the navigation properties on both ends of the relationship.
' Adding the newStudentGrade to newStudent will change newStudentGrade's status
' from Detached to Added.
newStudent.StudentGrades.Add(newStudentGrade)
' Navigation properties in both directions will work immediately.
Console.WriteLine("Access StudentGrades navigation property to get the count: ", _
newStudent.StudentGrades.Count)
Console.WriteLine("Access Person navigation property: {0} ", _
newStudentGrade.Person.FirstName)
context.SaveChanges()
End Using
using (var context = new SchoolEntities())
{
Person newStudent = new Person
{
// The database will generate PersonID.
// The object context will get the ID
// After the SaveChanges is called.
PersonID = 0,
LastName = "Li",
FirstName = "Yan"
};
StudentGrade newStudentGrade = new StudentGrade
{
// The database will generate EnrollmentID.
// The object context will get the ID
// After the SaveChanges is called.
EnrollmentID = 0,
Grade = 4.0M,
StudentID = 50
};
// Add newStudent to object context.
// The newStudent's state will change from Detached to Added.
context.People.AddObject(newStudent);
// To associate the new objects you can do one of the following:
// Add the new dependent object to the principal object: newStudent.StudentGrades.Add(newStudentGrade).
// Assign the reference (principal) object to the navigation property of the
// dependent object: newStudentGrade.Person = newStudent.
// Both of these methods will synchronize the navigation properties on both ends of the relationship.
// Adding the newStudentGrade to newStudent will change newStudentGrade's status
// from Detached to Added.
newStudent.StudentGrades.Add(newStudentGrade);
// Navigation properties in both directions will work immediately.
Console.WriteLine("Access StudentGrades navigation property to get the count: ",
newStudent.StudentGrades.Count);
Console.WriteLine("Access Person navigation property: {0} ", newStudentGrade.Person.FirstName);
context.SaveChanges();
}
Вместе с сопоставлением на основе внешнего ключа можно использовать ссылку для установления отношения, как это делалось в Entity Framework до версии 4.
' The following example creates a new StudentGrade and associates
' the StudentGrade with the Course and Person by
' setting the navigation properties to the Course and Person objects that were returned
' by the query.
' You do not need to call AddObject() in order to add the grade object
' to the context, because when you assign the reference
' to the navigation property the objects on both ends get synchronized by the Entity Framework.
' Note, that the Entity Framework will not synchronize the ends untill the SaveChanges method
' is called if your objects do not meet the change tracking requirements.
Using context = New SchoolEntities()
Dim courseID = 4022
Dim course = (From c In context.Courses
Where c.CourseID = courseID
Select c).First()
Dim personID = 17
Dim student = (From p In context.People
Where p.PersonID = personID
Select p).First()
' The database will generate the EnrollmentID.
' Use the navigation properties to create the association between the objects.
Dim newStudentGrade = New StudentGrade With
{
.EnrollmentID = 0,
.Grade = CDec(4.0),
.Course = course,
.Person = student
}
context.SaveChanges()
End Using
// The following example creates a new StudentGrade and associates
// the StudentGrade with the Course and Person by
// setting the navigation properties to the Course and Person objects that were returned
// by the query.
// You do not need to call AddObject() in order to add the grade object
// to the context, because when you assign the reference
// to the navigation property the objects on both ends get synchronized by the Entity Framework.
// Note, that the Entity Framework will not synchronize the ends untill the SaveChanges method
// is called if your objects do not meet the change tracking requirements.
using (var context = new SchoolEntities())
{
int courseID = 4022;
var course = (from c in context.Courses
where c.CourseID == courseID
select c).First();
int personID = 17;
var student = (from p in context.People
where p.PersonID == personID
select p).First();
StudentGrade grade = new StudentGrade
{
// The database will generate the EnrollmentID.
Grade = 4.0M,
// Use the navigation properties to create the association between the objects.
Course = course,
Person = student
};
context.SaveChanges();
}
Следующий пример показывает простое взаимодействие между клиентом и службой, когда клиент запрашивает объект из службы, обновляет объект и вызывает службу для сохранения изменений в базе данных.
Служба определяет два метода:
Private Shared Function GetOriginalValue(ByVal ID As Integer) As StudentGrade
Dim originalItem As StudentGrade
Using context As New SchoolEntities()
originalItem = context.StudentGrades.Where(Function(g) g.EnrollmentID = ID).FirstOrDefault()
context.Detach(originalItem)
End Using
Return originalItem
End Function
Private Shared Sub SaveUpdates(ByVal updatedItem As StudentGrade)
Using context As New SchoolEntities()
' Query for the StudentGrade object with the specified ID.
Dim original = (From o In context.StudentGrades
Where o.EnrollmentID = updatedItem.EnrollmentID
Select o).First()
' Apply changes.
context.StudentGrades.ApplyCurrentValues(updatedItem)
' Save changes.
context.SaveChanges()
End Using
End Sub
static private StudentGrade GetOriginalValue(int ID)
{
StudentGrade originalItem;
using (SchoolEntities context
= new SchoolEntities())
{
originalItem =
context.StudentGrades.Where(g => g.EnrollmentID == ID).FirstOrDefault();
context.Detach(originalItem);
}
return originalItem;
}
static private void SaveUpdates(StudentGrade updatedItem)
{
using (SchoolEntities context
= new SchoolEntities())
{
// Query for the StudentGrade object with the specified ID.
var original = (from o in context.StudentGrades
where o.EnrollmentID == updatedItem.EnrollmentID
select o).First();
// Apply changes.
context.StudentGrades.ApplyCurrentValues(updatedItem);
// Save changes.
context.SaveChanges();
}
}
Клиент обновляет значения свойств внешнего ключа и передает обновленный объект службе:
' A client calls a service to get the original object.
Dim studentGrade As StudentGrade = GetOriginalValue(3)
' Change the relationships.
studentGrade.CourseID = 5
studentGrade.StudentID = 10
' The client calls a method on a service to save the updates.
// A client calls a service to get the original object.
StudentGrade studentGrade = GetOriginalValue(3);
// Change the relationships.
studentGrade.CourseID = 5;
studentGrade.StudentID = 10;
// The client calls a method on a service to save the updates.
SaveUpdates(studentGrade);
См. также
Основные понятия
Определение отношений и управление отношениями (платформа Entity Framework)
Работа с сущностями POCO (платформа Entity Framework)