根据reference source DbSet.Find,如果在 DbContext 中已经获取了具有相同 keyValues 的对象,则不会访问数据库:
/// Finds an entity with the given primary key values.
/// If an entity with the given primary key values exists in the context, then it is
/// returned immediately without making a request to the store.
public abstract object Find(params object[] keyValues);
FirstOrDefault,类似的函数会调用IQueryable.GetEnumerator(),它会向IQueryable询问ProviderIQueryable.GetProvider()的接口,然后调用IQueryProvider.Execute(Expression)来获取Expression定义的数据。
这将始终访问数据库。
假设你有学校和他们的学生,一个简单的一对多关系。您还有一个更改学生数据的程序。
Student ChangeAddress(dbContext, int studentId, Address address);
Student ChangeSchool(dbContext, int studentId, int SchoolId);
您在程序中有这个,因为这些程序会检查更改的有效性,可能伊顿学生不允许住在牛津校区,并且可能有些学校只允许特定年龄的学生。
您有以下代码使用这些过程:
void ChangeStudent(int studentId, Address address, int schoolId)
{
using (var dbContext = new SchoolDbContext())
{
ChangeAddress(dbContext, studentId, address);
ChangeSchool(dbContext, studentId, schoolId);
dbContext.SaveChanges();
}
}
如果 Change... 函数将使用 FirstOrDefault(),那么您将丢失其他过程所做的更改。
但是,有时您希望能够重新获取数据库数据,例如,因为其他人可能已经更改了数据,或者您刚刚所做的某些更改无效
Student student = dbContext.Students.Find(10);
// let user change student attributes
...
bool changesAccepted = AskIfChangesOk();
if (!changesAccepted)
{ // Refetch the student.
// can't use Find, because that would give the changed Student
student = dbContext.Students.Where(s => s.Id == 10).FirstOrDefault();
}
// now use the refetched Student with the original data