#.net #performance #entity-framework-4.1
#.net #Производительность #entity-framework-4.1
Вопрос:
Я запускаю сценарии тестирования, чтобы решить, следует ли внедрять систему с использованием Entity Framework, и сталкиваюсь с интересным вопросом. У меня есть коллекция объектов ‘PersonCollectable’, хранящихся в ‘Person’, и каждый ‘PersonCollectable’ ссылается на ‘Страницу’; извлечение коллекции предоставляет мне все объекты ‘PersonCollectable’, которые я хочу отобразить, но я также хочу отобразить имя ‘Page’. Приведет ли это к запросу для каждой страницы и, следовательно, негативно повлияет на производительность?
public class Person
{
public virtual ICollection<PersonCollectable> Collection { get; set; }
public int Id { get; set; }
public string Name { get; set; }
}
public class PersonCollectable
{
public int Id { get; set; }
public virtual Page Page { get; set; }
public int PageId { get; set; }
}
public class Page
{
public int Id { get; set; }
public string Name { get; set; }
}
И это тестовый код для извлечения информации и отображения результатов. Представьте, что коллекция заполнена по крайней мере 500 элементами, так что это может привести к 500 дополнительным запросам на веб-запрос. Машина разработки может справиться с этим, но я хотел бы знать, приведет ли это к уничтожению опубликованного продукта.
Person example = db.People.Single( s => s.Name == "Roel" );
foreach( PersonCollectable exampleCollectable in example.Collection ) {
Console.WriteLine( "{0} rated {1}", exampleCollectable.Page.Name, exampleCollectable.Rating );
}
Пожалуйста, поделитесь своим пониманием и помогите мне ответить на этот вопрос, приведет ли это к запросу для каждой страницы и, следовательно, негативно повлияет на производительность?Спасибо.
Ответ №1:
Да, это приведет к 500 запросам, потому что ваш способ загрузки свойств навигации основан на отложенной загрузке ( virtual
свойства навигации).
Если вы хотите загрузить весь граф объектов за один шаг / туда и обратно в БД, вы должны сообщить об этом, используя Include
при запуске запроса:
Person example = db.People
.Include(s => s.Collection.Select(c => c.Page))
.Single(s => s.Name == "Roel");
(Оставшийся код может остаться неизменным.)
В вашем конкретном случае рекомендуемый способ — использовать проекцию, хотя это означает, что вы загружаете только те свойства, которые вам нужны:
var example = db.People
.Where(s => s.Name == "Roel")
.Select(s => new
{
PersonName = s.Name,
CollectedData = s.Collection.Select(c => new
{
PageName = c.Page.Name,
Rating = c.Rating
})
})
.Single();
Console.WriteLine( "Person {0}:", example.PersonName);
foreach(var item in example.CollectedData)
{
Console.WriteLine( "{0} rated {1}", item.PageName, item.Rating );
}
Вместо использования анонимного типа вы также можете создать свой собственный именованный тип «View» и спроецировать на него с помощью и т.д. Select(s => new MyViewType...)
Комментарии:
1. Спасибо! Это очень понятное решение, которое дало мне некоторое представление о том, как работают EF и Linq, о чем стоит подумать при дальнейшем использовании EF. Еще раз спасибо за ваш быстрый, точный и понятный ответ.