У меня есть существующий объект, который я хотел бы обновить с помощью последних данных из моей базы данных. В настоящее время я могу получить объект EF Core, а затем вызвать Mapper.Map для обновления своего dto. Есть ли способ использовать ProjectTo (или что-то подобное) для обновления моего объекта из базы данных?
Вместо этого:
var result = await context.DbSet
.FirstOrDefaultAsync(e => e.Id == id, cancellationToken: cancellationToken)
.ConfigureAwait(false);
return Mapper.Map(result, existingObject);
Как я могу:
var result = await context.DbSet
.ProjectTo<TDest>(/* existingObject */) // I tried .Map, but I got an error that automapper was trying to map this to a child object
.FirstOrDefaultAsync(e => e.Id == id, cancellationToken: cancellationToken)
.ConfigureAwait(false);
return existingObject; // Where existingObject contains the latest database information
Я бы попытался использовать DbSet.Select()
Автосопоставитель карты. Он ничего не знает о базах данных или обновлениях. Он даже не нужен для работы с EF Core, он используется только для упрощения сопоставления длинных DTO базы данных с, например, DTO API на основе соглашений, выравнивания и т. д. ProjectTo(configuration)
ожидает объект конфигурация, который указывает, как сопоставлять один DTO с другим.
Почему вы пытаетесь изменить существующие объекты? Вы все равно загружаете объекты базы данных, почему бы их не использовать?
PS: документация объясняет, для чего используется ProjectTo. Это также объясняет, что это должен быть последний вызов в запросе.
@PanagiotisKanavos Спасибо за комментарии. Поэтому я должен: а) вызвать Where перед ProjectTo и не использовать фильтр в FirstOrDefault? б) Я исходил из того, что ProjectTo обходит создание объекта объекта и записывает непосредственно в dto, я ошибаюсь в этом? и в) то, на что я надеялся, не существует? Мне нужно будет получить объект сущности, а затем отобразить его, как я это делаю сейчас (мой первый пример)?
Не уверен, насколько это полезно, но вы можете использовать следующее расширение:
public static class MappingExtensions
{
public static async Task<TDest> ProjectToObjAsync<TDest>(this IQueryable source, IMapper mapper, TDest obj, cancellationToken cancellationToken = default)
{
var loadedObj = await source.ProjectTo<TDest>(mapper.Configuration).FirstOrDefaultAsync(cancellationToken);
if (loadedObj != null)
{
mapper.Map(loadedObj, obj);
}
return obj;
}
}
И использование:
var result = await context.DbSet
.Where(e => e.Id == id)
.ProjectToObjAsync(Mapper, existingObject, cancellationToken)
.ConfigureAwait(false);
return existingObject;
@PanagiotisKanavos, как мне загрузить всю таблицу вызовом FirstOrDefaultAsync
? Пожалуйста, начните читать, прежде чем оставлять комментарии.
Я неправильно понял, как работает ProjectTo
. Это по-прежнему оставляет этот ответ не лучше, чем исходный код
Заметил в первом предложении, что не вижу смысла в таком методе.
документы предостерегают от использования такого кодаProjectTo must be the last call in the chain. ORMs work with entities, not DTOs. So apply any filtering and sorting on entities and, as the last step, project to DTOs.
Вот почему я предположил, что метод действительно выполняет результаты.
@PanagiotisKanavos, даже хуже, я знаю, как ProjectTo
работает внутри. Это использование правильно
Это просто обновило объект EF из базы данных, когда я использую DTO с AutoMapper, я не сохраняю ссылку на исходный объект. Я могу получить последние данные из базы данных, я просто надеюсь, что есть способ обновить мой DTO непосредственно из запроса, а не отображать объект EF.