ASP.NET Web API возвращают запрашиваемые DTO?
Я создал симпатичный маленький API с помощью ASP.NET Web API, но, полагаю, неправильно возвращать сущности из моего контекста (каркас сущностей) AsQueryable, поэтому я сопоставляю все с объектами DTO.
Однако, что я не совсем понимаю: как я могу сохранить свой контекст запрашиваемым, но по-прежнему только возвращать DTO вместо сущностей? Или это невозможно?
Это мой код:
public IQueryable<ItemDto> Get()
{
using (EfContext context = new EfContext())
{
Mapper.CreateMap<Item, ItemDto>()
.ForMember(itemDto => itemDto.Category, mce => mce.MapFrom(item => item.Category.Name));
IEnumerable<ItemDto> data = Mapper.Map<IEnumerable<Item>, IEnumerable<ItemDto>>(context.Items
.OrderByDescending(x => x.PubDate)
.Take(20));
return data.AsQueryable();
}
}
Как видите, я загружаю данные и делаю эту маленькую коллекцию IEnumerable запрашиваемой. Проблема в том, что запрос, сгенерированный для этого фрагмента кода, вероятно, довольно неэффективен, поскольку сначала он загружает все элементы (или, по крайней мере, 20 первых элементов), а затем фильтрует выходные данные.
Надеюсь, я описал свою проблему как можно лучше, это немного сложно объяснить. Я не мог найти ничего об этом в Google.
3 ответа
Не выбирайте все в памяти в первую очередь. Сделайте что-то вроде этого:
public IQueryable<ItemDto> Get()
{
using (EfContext context = new EfContext())
{
var query = from item in context.Items
select Mapper.Map<Item, ItemDto>(item)
return query.OrderByDescending(x => x.PubDate).Take(20));
}
}
Кстати, следующий код - это то, что вы хотите сделать один раз, например, в статическом конструкторе или в WebApiConfig.cs
файл.
Mapper.CreateMap<Item, ItemDto>()
.ForMember(itemDto => itemDto.Category, mce => mce.MapFrom(item => item.Category.Name));
Если в коде, который мы видим (т. Е. Упорядочение и прием), происходит только запрос, ваш код в порядке. Он будет отображать только результат (максимум 20). Тем не менее, так как вы возвращаете IQueryable, я предполагаю, что вы хотели бы дополнительно запросить результат. Может быть параметры стиля OData?
С максимум 20 предметами вам, вероятно, лучше не писать никакого кода. Остальные запросы будут выполняться как объектные запросы. Однако, если вы решите удалить это ограничение (максимум 20) или поставить его после выполнения дальнейших запросов, этот способ будет неэффективным.
По сути, вам нужно переместить отображение в самый конец цепочки запросов, если вы хотите, чтобы все ваши запросы выполнялись в базе данных EF.
Что вы можете сделать, это на самом деле вернуть фактические объекты сущности
public IQueryable<ItemDto> Get()
{
using (EfContext context = new EfContext())
{
return context.items
.OrderByDescending(x => x.PubDate)
.Take(20));
}
}
И скажите MVC, как сериализовать это в MediaTypeFormatter. Здесь вы можете использовать AutoMapper.
http://dotnetplusplus.wordpress.com/2013/08/30/odata-web-apis-with-automapper-3/
Используйте return _itemRepository.GetItemsQuery () .Project (). To ();