实体框架 4 - 列表基于 T 的子属性的 Order By

发布于 2024-11-02 14:42:18 字数 427 浏览 2 评论 0 原文

我有以下代码 -

 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?

谢谢!

I have the following code -

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

I'm trying to sort the list of the contacts according to the area name that is contained within each contact. When I tried the above, I get "At least one object must implement IComparable.". Is there an easy way instead of writing a custom IComparer?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

分开我的手 2024-11-09 14:42:18

试试这个:

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

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

希望这有帮助:)

编辑:修复了代码中的错误。 (.First().名称)

try this:

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

this will order the contacts by the first area name, after ordering the areas by name.

Hope this helps :)

Edit: fixed error in code. (.First().Name)

战皆罪 2024-11-09 14:42:18

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

他的答案有效,但此代码中存在两个性能问题(都在原始问题的答案中)。

首先,代码加载数据库中的所有联系人。这可能是也可能不是问题,但一般来说我建议不要这样做。许多现代控件支持开箱即用的分页/过滤,因此您最好提供尚未评估的 IQueryable 而不是 List 。但是,如果您需要内存中的所有内容,则应将 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();
    }
}

I was in a discussion with @AbdouMoumen but in the end I thought I'd provide my own answer :-)

His answer works, but there two performance issues in this code (both in the answer as in the original question).

First, the code loads ALL contacts in the db. This may or may not be a problem, but in general I would recommend NOT to do this. Many modern controls support paging/filtering out of the box, so you'd be better off supplying an not-yet-evaluated IQueryable<T> instead of List<T>. If however you need everything in memory, you should delay the ToList to the last possible moment.

Second, in AbdouMoumen's answer, there is a so-called 'SELECT N+1' problem. Entity Framework will by default use lazy loading to fetch additional properties. I.e. the Areas property will not be fetched from the database until it's accessed. In this case this will happen in the controls 'for loop', while it's ordering the result set by name.

Open up SQL Server Profiler to see what I mean: you will see a SELECT statement for all the contacts, and an additional SELECT statement for each contact that fetches the Areas for that contact.

A much better solution would be the following:

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();
    }
}
我还不会笑 2024-11-09 14:42:18

是一对一的关系(联系人->区域)吗?
如果是,请尝试以下操作:

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

Is it one to one relation (Contact->Area)?
if yeah then try the following :

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

then

grdItems.DataSource = contacts.OrderBy(x => x.AreaName);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文