实体框架4 - 列出<t>基于T的子项属性的订单</t>

时间:2011-04-20 11:30:38

标签: linq entity-framework entity sql-order-by generic-list

我有以下代码 -

 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 个答案:

答案 0 :(得分:3)

试试这个:

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();
}

这将按照名称命名区域后按第一个区域名称对联系人进行排序。

希望这会有所帮助:)

编辑:修复了代码中的错误。 (。首先()。命名

答案 1 :(得分:2)

我和@AbdouMoumen正在讨论,但最后我想我会提供自己的答案: - )

他的回答有效,但此代码中有两个性能问题(答案与原始问题一样)。

首先,代码加载db中的所有联系人。这可能是也可能不是问题,但一般情况下我建议不要这样做。许多现代控件都支持开箱即用的分页/过滤功能,因此您最好不要提供尚未评估的IQueryable<T>代替List<T>。但是,如果您需要内存中的所有内容,则应将ToList延迟到最后一刻。

其次,在AbdouMoumen的回答中,有一个所谓的“SELECT N + 1”问题。实体框架默认使用延迟加载来获取其他属性。即在访问之前,不会从数据库中获取Areas属性。在这种情况下,这将在控件'for循环'中发生,而它按名称排序结果集。

打开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();
    }
}

答案 2 :(得分:1)

是一对一关系(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);