Должны ли мы всегда использовать .Find (), а не .FirstOrDefault (), когда у нас есть первичный ключ в Entity Framework Core? - PullRequest
2 голосов
/ 09 ноября 2019

https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/details?view=aspnetcore-3.0

В примере документации Microsoft .FirstOrDefaultAsync() используется в Detail и Delete GET;.FindAsync() используется в DeleteConfirmed. Интересно, почему это так?

Ответы [ 2 ]

3 голосов
/ 09 ноября 2019

Согласно справочному источнику DbSet.Find не будет обращаться к базе данных, если в 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 и аналогичными функциями. вызовет IQueryable.GetEnumerator(), который запросит у IQueryable интерфейс для провайдера IQueryable.GetProvider(), а затем вызовет IQueryProvider.Execute(Expression), чтобы получить данные, определенные выражением. Это всегда будет иметь доступ к базе данных.

Предположим, у вас есть школы со своими учениками, простые отношения один ко многим. У вас также есть процедуры для изменения данных учеников.

Student ChangeAddress(dbContext, int studentId, Address address);
Student ChangeSchool(dbContext, int studentId, int SchoolId);

У вас есть такие процедуры, потому что эти процедуры проверят действительность изменений, возможно, студентам Eton не разрешено жить в кампусе Оксфорда, и тамэто могут быть школы, в которых разрешено обучение только ученикам определенного возраста.

У вас есть следующий код, который использует следующие процедуры:

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
1 голос
/ 09 ноября 2019

Я думаю, это потому, что при удалении вы не знаете, существует ли элемент или нет, поэтому вам нужно использовать значение по умолчанию, если он не найден.

При выполнении DeleteConfirmed вы знаете элемент с id существует и может использовать Find.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...