If you are using DbContext (EF >= 4.1):
dbContext.Departments.Attach(dep);
dep.Courses = dbContext.Entry(dep).Collection(d => d.Courses).Query()
.Include(c => c.Students)
.Where(c => c.level == "Master")
.ToList();
If you are using ObjectContext with EntityObject derived entities (not POCOs):
objectContext.Departments.Attach(dep);
dep.Courses.Attach(dep.Courses.CreateSourceQuery()
.Include("Students")
.Where(c => c.level == "Master")
.ToList());
If you are using ObjectContext with POCOs it's possible but a bit hairy.
All queries above are actually not the same like yours because maybe your dep.Courses collection does not contain all the courses that are related to the department dep in the database. (Who knows if you didn't remove a course from the dep.Courses collection after loading it?) In this case I'm afraid your query is the only way to go.
Because you were talking about performance and database request optimization: If you want to avoid the overhead to load the courses again (which you already have in memory) you could also try:
courseIDs = dep.Courses
.Where(c => c.level == "Master").Select(c => c.courseID);
var studentDict = dbcontext.Courses
.Where(c => courseIDs.Contains(c.courseID))
.Select(c => new
{
courseID = c.courseID,
Students = c.Students
})
.ToDictionary(x => x.courseID, x => x.Students);
foreach (var course in dep.Courses)
course.Students = studentDict[course.courseID];
It loads less data but is not necessarily more performant because Contains has significant costs of translation into SQL for large courseIDs collections.