According to the reference source DbSet.Find will not access the database if an object with the same keyValues is already fetched in the DbContext:
/// 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, and similar functions will call IQueryable.GetEnumerator(), which will ask the IQueryable for the interface to the Provider IQueryable.GetProvider() and then call IQueryProvider.Execute(Expression) to get the data defined by the Expression.
This will always access the database.
Suppose you have Schools with their Students, a simple one-to-many relationship. You also have a procedures to change Student data.
Student ChangeAddress(dbContext, int studentId, Address address);
Student ChangeSchool(dbContext, int studentId, int SchoolId);
You have this in procedures, because these procedure will check the validity of the changes, probably Eton Students are not allowed to live on Oxford Campus, and there might be Schools that only allow Students from a certain age.
You have the following code that uses these procedures:
void ChangeStudent(int studentId, Address address, int schoolId)
{
using (var dbContext = new SchoolDbContext())
{
ChangeAddress(dbContext, studentId, address);
ChangeSchool(dbContext, studentId, schoolId);
dbContext.SaveChanges();
}
}
If the Change... functions would use FirstOrDefault() then you would lose changes made by the other procedure.
However, sometimes you want to be able to re-fetch the database data, for instance, because others might have changed the data, or some changes you just made are invalid
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