Entity Framework 4 - List <T>Order By на основе детской собственности T - PullRequest
0 голосов
/ 20 апреля 2011

У меня есть следующий код -

 public void LoadAllContacts()
        {
            var db = new ContextDB();
            var contacts = db.LocalContacts.ToList();
            grdItems.DataSource = contacts.OrderBy(x => x.Areas.OrderBy(y => y.Name));
            grdItems.DataBind();
        }

Я пытаюсь отсортировать список контактов по названию области, содержащейся в каждом контакте.Когда я попробовал описанное выше, я получил «По крайней мере, один объект должен реализовывать IComparable».Есть ли простой способ вместо написания собственного IComparer?

Спасибо!

Ответы [ 3 ]

3 голосов
/ 20 апреля 2011

попробуйте это:

public void LoadAllContacts()
{
    var db = new ContextDB();
    var contacts = db.LocalContacts.ToList();
    grdItems.DataSource = contacts.OrderBy(x => x.Areas.OrderBy(y => y.Name).First().Name);
    grdItems.DataBind();
}

это упорядочит контакты по имени первой области, после упорядочивания областей по имени.

Надеюсь, это поможет:)

Редактировать : исправлена ​​ошибка в коде. (.Первый (). Имя )

2 голосов
/ 02 мая 2011

Я был в дискуссии с @AbdouMoumen, но в конце концов я решил дать свой собственный ответ: -)

Его ответ работает, но в этом коде есть две проблемы с производительностью (оба в ответекак в оригинальном вопросе).

Сначала код загружает ВСЕ контакты в БД.Это может быть или не быть проблемой, но в целом я бы рекомендовал НЕ делать этого.Многие современные элементы управления поддерживают подкачку / фильтрацию «из коробки», так что вам лучше поставить еще не оцененный IQueryable<T> вместо List<T>.Однако, если вам нужно все в памяти, вы должны отложить ToList до последнего возможного момента.

Во-вторых, в ответе AbdouMoumen есть так называемая проблема «ВЫБОР N + 1».По умолчанию Entity Framework будет использовать отложенную загрузку для получения дополнительных свойств.Т.е. свойство Areas не будет извлечено из базы данных, пока к нему не будет получен доступ.В этом случае это произойдет в элементе управления for loop, в то время как он упорядочивает результат по имени.

Откройте SQL Server Profiler, чтобы понять, что я имею в виду: вы увидите инструкцию SELECT для всех контактов и дополнительную инструкцию SELECT для каждого контакта, которая выбирает области для этого контакта.

Гораздо лучшим решением было бы следующее:

public void LoadAllContacts()
{
    using (var db = new ContextDB())
    {

        // note: no ToList() yet, just defining the query 
        var contactsQuery = db.LocalContacts
            .OrderBy(x => x.Areas
                       .OrderBy(y => y.Name)
                       .First().Name);  

        // fetch all the contacts, correctly ordered in the DB
        grdItems.DataSource = contactsQuery.ToList();

        grdItems.DataBind();
    }
}
1 голос
/ 20 апреля 2011

Это отношение один к одному (Contact->Area)?
если да, то попробуйте следующее:

public partial class Contact
{
    public string AreaName
    {
        get
        {
            if (this.Area != null)
               return this.Area.Name;
            return string.Empty;
        }
     }
 }

затем

grdItems.DataSource = contacts.OrderBy(x => x.AreaName);
...