Utilizzo di chiavi esterne (Entity Framework)
A partire da .NET Framework versione 4, è possibile esporre proprietà di chiave esterna sui tipi di entità e definire relazioni tramite chiavi esterne. L'opzione Includi colonne di chiavi esterne nel modello nella Procedura guidata Entity Data Model è selezionata per impostazione predefinita. Quando questa opzione è selezionata, gli oggetti entità generati dispongono di proprietà scalari con mapping alle colonne di chiavi esterne.
Le proprietà di chiave esterna consentono di creare o modificare una relazione senza eseguire una query per individuare l'oggetto Principal. Quando si includono proprietà di chiave esterna, è comunque possibile modificare una relazione aggiornando il riferimento all'oggetto Principal nell'oggetto dipendente o aggiungendo un oggetto dipendente a una raccolta nell'oggetto Principal. Una soluzione comune per accedere ai riferimenti e alle raccolte nelle entità consiste nell'utilizzare le proprietà di navigazione. Per ulteriori informazioni, vedere Proprietà di navigazione.
Entity Framework tenta di tenere sincronizzati i riferimenti, le raccolte e le proprietà di chiave esterna. Se si aggiorna una proprietà di chiave esterna di un oggetto dipendente, il riferimento in questo oggetto e la raccolta nell'oggetto Principal devono essere sincronizzati. Affinché questa sincronizzazione si verifichi, le entità devono essere associate al contesto dell'oggetto e devono essere rilevate da Entity Framework . Per ulteriori informazioni, vedere Risoluzione di identità, gestione dello stato e rilevamento delle modifiche (Entity Framework) e Definizione e gestione delle relazioni (Entity Framework).
Gli esempi inclusi in questo argomento sono basati sul modello descritto in Modello School. I tipi di entità inclusi in questi esempi vengono generati dagli strumenti Entity Data Model . I tipi generati vengono rilevati da Entity Framework. Se si utilizzano tipi POCO, vedere Rilevamento delle modifiche nelle entità POCO (Entity Framework).
Nell'esempio seguente viene illustrato come modificare la relazione tra due oggetti esistenti.
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();
}
Nell'esempio seguente viene illustrato come impostare la relazione tra il nuovo oggetto dipendente e gli oggetti Principal esistenti impostando le proprietà di chiave esterna.
' 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();
}
Nell'esempio seguente viene illustrato come impostare la relazione tra il nuovo oggetto dipendente e il nuovo oggetto principale.
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();
}
Con l'associazione delle chiavi esterne, è comunque possibile utilizzare il riferimento per impostare la relazione come si farebbe nella versione precedente a 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();
}
Di seguito è illustrata una comunicazione semplice tra un client e un servizio, in cui il client richiede un oggetto al servizio, il client aggiorna l'oggetto e chiama il servizio per salvare le modifiche nel database.
Il servizio definisce due metodi:
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();
}
}
Il client aggiorna i valori delle proprietà di chiave esterna e invia l'oggetto aggiornato al servizio:
' 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);
Vedere anche
Concetti
Definizione e gestione delle relazioni (Entity Framework)
Utilizzo di entità POCO (Entity Framework)