С EF вы захотите использовать Select()
для сопоставления сущностей с вашим DTO, хотя вам нужно будет рассмотреть всю структуру DTO. Например, из чего будет состоять структура данных «Журналы»? Это одно строковое значение, список строк или список записей журнала?
Используя Select()
, вам нужно использовать установщики свойств, а не конструктор, принимающий сущность.
Итак, шаблон такой:
public class Entity
{
public string Field { get; set; }
}
public class Dto
{
public string Field { get; set; }
}
var dtos = context.Entities
.Where(x => x.IsActive)
.Select(x => new Dto
{
Field = x.Field
})
.ToList();
Глядя на ваш пример с конструктором:
открытый класс Dto
{
публичная строка Field {get; приватный набор; } * +1010 *
public Dto(Entity entity)
{
Field = entity.Field;
}
}
var dtos = context.Entities
.Where(x => x.IsActive)
.Select(x => new Dto(x))
.ToList();
Это не работает с EF & Select. EF может отображаться на объект, но только через свойства и конструктор без параметров. Об этом нужно знать, но избегайте, если вы его видите:
var dtos = context.Entities
.Where(x => x.IsActive)
.ToList()
.Select(x => new Dto(x))
.ToList();
С дополнительным ToList()
перед выбором вызов будет работать, потому что EF выполнит запрос и возвратит список сущностей, тогда Select()
будет выполнен как запрос Linq2Object. Причина, по которой вам следует избегать этого, заключается в том, что EF выберет все свойства из сущности, где нам следует только вернуть те свойства, которые нам нужны. Также легко попасть в ловушку производительности с ленивой нагрузкой, если ваша совокупность конструкторов Dto начнет перебирать связанные сущности. Использование Select
для загрузки только тех полей, которые вам нужны от сущности и любых связанных сущностей, позволяет EF создавать эффективный запрос только для необходимых данных без каких-либо отложенных прерываний загрузки.
Используя AutoMapper, вы можете упростить это, настроив сопоставление от сущности до DTO, затем используя ProjectTo<Dto>()
.
Итак, если вы хотите, чтобы DTO представлял результаты (такие как флаг успеха, сообщение об ошибке) с коллекцией результатов в случае успеха:
[Serializable]
// Our results container.
public class SearchResultsDTO
{
public bool IsSuccessful { get; private set; } = false;
public string ErrorMessage { get; private set; }
public ICollection<SearchResultDTO> Results { get; private set; } = new List<SearchResultDTO>();
private SearchResultsDTO() {}
public static SearchResultsDTO Success(ICollection<SearchResultDTO> results)
{
var results = new SearchResultsDTO
{
IsSuccessful = true,
Results = results
};
return results;
}
public static SearchResultsDTO Failure(string errorMessage)
{
var results = new SearchResultsDTO
{
ErrorMessage = errorMessage
};
return results;
}
}
[Serializable]
public class SearchResultDTO
{
public int ID {get; set;}
public string Name {get; set;}
public string Job {get; set;}
public DateTime Start {get; set;}
public DateTime End {get; set;}
public ICollection<string> Logs {get; set;} = new List<string>();
}
затем заполнить их из DbContext: (внутри репозитория или везде, где считываются данные)
using (var context = new SearchContext())
{
var results = context.Logs
.Where(x => x.Name.Contains(sRequest))
.Select(x => new SearchResultDTO
{
ID = x.ID,
Name = x.Name,
Job = x.Job,
Start = x.Start,
End = x.End,
Logs = x.LogLines.Select(y => y.Line).ToList(),
}).ToList();
var resultDto = SearchResultsDTO.Success(results);
return resultsDto;
}
Предполагается, что запись в журнале содержит задание, имя, начало, дату и время окончания, а затем список «строк» или записей для отображения как «Журналы». (Там, где таблица Log имеет связанную таблицу LogLine, например, с одной или несколькими строками). Это демонстрирует, как использовать Select
для отображения не только записи журнала в DTO, но и для отображения связанных записей в нечто вроде набора Строки или набор других DTO также могут быть сделаны.
Как только он выбирает DTO, он заполняет контейнер DTO, используя статические фабричные методы, чтобы заполнить либо успешное чтение, либо неудачное чтение. (который может быть установлен в обработчике исключений, например.) В качестве альтернативы вы можете просто создать новый класс контейнера и заполнить свойства, использовать параметры конструктора / w или просто вернуть список DTO. Контейнер SearchResultsDTO - , а не , на который ссылается запрос EF.