Коллекция Entity Framework 4.1 с влиянием ссылок на производительность?

#.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. Еще раз спасибо за ваш быстрый, точный и понятный ответ.