有序的区别

时间:2012-09-18 15:19:53

标签: c# linq sql-order-by distinct

我有以下

IList<Project> projects = (from update in dbContext.TicketUpdates
               where update.TicketUpdatesEmployeeID == Profile.EmployeeID
               orderby update.TicketUpdatesEndDate descending
               select update.Ticket.Project).Distinct().ToList();

我知道Distinct()并不保证订单,但之后我无法对其进行重新排序,因为投影会丢失我用来订购的字段。我该如何解决这个问题?

3 个答案:

答案 0 :(得分:1)

使用GroupBy的新解决方案
更新的 实际上有一个更简单的解决方案:

IList<Project> projects = (from update in dbContext.TicketUpdates where update.TicketUpdatesEmployeeID == Profile.EmployeeID)
    .GroupBy(tu=>tu.Ticket.Project)
    .Select(group=>group.First())
    .OrderByDescending(tu=>tu.TicketUpdatesEndDate)
    .Select(tu=>tu.Ticket.Project)
    .ToList();

(我刚看到这篇文章时,其他人也发了类似的答案)


使用自定义IEqualityComparer的旧解决方案(我不确定这是否适用于linq2sql)

有一个Distinct overload that takes a custom IEqualityComparer。因此,在投影数据之前,使用自定义IEqualityComparer 对TicketUpdates进行区分。

如果IEqualityComparer具有相同的项目,则它应将所有TicketUpdates统计为相等。这样,具有相同项目的TicketUpdates将被丢弃。

(请注意,您不会控制哪个具有相同项目的TicketUpdates将被丢弃。因此,如果这些具有相同项目的TicketUpdates具有不同的EndDates,则需要一个涉及GroupBy的解决方案。

IList<Project> projects = (from update in dbContext.TicketUpdates where update.TicketUpdatesEmployeeID == Profile.EmployeeID)
    .Distinct(new ProjectComparer())
    .OrderByDescending(tu=>tu.TicketUpdatesEndDate)
    .Select(tu=>tu.Ticket.Project)
    .ToList();


// Your comparer should look somewhat like this 
// (untested code! And I do not know all the details about your class structure)
class ProjectComparer : IEqualityComparer<TicketUpdates>
{
    // Products are equal if their names and product numbers are equal. 
    public bool Equals(TicketUpdates x, TicketUpdates y)
    {

        //Check whether the compared objects reference the same data. 
        if (Object.ReferenceEquals(x, y)) return true;

        //Check whether any of the compared objects is null. 
        if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
            return false;

        //Check whether projects are equal. 
        //(perhaps do a null check for Ticket!)
        return x.Ticket.Project== y.Ticket.Project;
    }

    // If Equals() returns true for a pair of objects  
    // then GetHashCode() must return the same value for these objects. 

    public int GetHashCode(TicketUpdates x)
    {
        //Check whether the object is null 
        if (Object.ReferenceEquals(x, null)) return 0;

        // null check for Ticket and Project?
        return x.Ticket.Project.GetHashCode();
    }

}

答案 1 :(得分:1)

我认为最好的办法是发布流程以保持订购:

var projects = (from update in dbContext.TicketUpdates
           where update.TicketUpdatesEmployeeID == Profile.EmployeeID
           orderby update.TicketUpdatesEndDate descending
           select update.Ticket.Project);
var seen = new HashSet<Project>();
foreach (var project in projects)
{
    if (seen.Add(project))
    {
        // A distinct project
    }
}

或者你可以滥用 GroupBy

var projects = dbContext.TicketUpdates
    .Where(uu => uu.TicketUpdatesEmployeeID == Profile.EmployeeID)
    .GroupBy(uu => uu.Ticket.Project)
    .OrderByDescending(gg => gg.Max(uu => uu.TicketUpdatesEndDate))
    .Select(gg => gg.Key);

GroupBy之间使用uu.Ticket.Project,每个更新都会按其关联的项目进行分组。如果你有10个项目和30个更新,那么你将在该阶段的输出中有10个组 - 每个项目一个。接下来,我们按照最新的结束日期对组进行排序,保留您要查找的降序。最后,我们从项目的每个IGrouping中选择密钥。

答案 2 :(得分:0)

您可以使用GroupBy运算符获取唯一记录,然后在新记录集上执行订单。

var projectList = dbContext.TicketUpdates.GroupBy(p => p.TicketUpdatesEmployeeId)
                    .Where( r => r.TicketUpdatesEmployeeId == Profile.EmployeeId)
                    .Select(r => r.First())
                    .OrderByDesc(q => q.TicketUpdatesEndDate)
                    .Select(n => n.First()).Ticket.Project;