根据另一个IQueryable的值排序IQueryable

本文关键字:IQueryable 排序 另一个 | 更新日期: 2023-09-27 18:10:55

我有两个IQueryables从Linq返回到SQL,我想按另一个排序。这就是我要写的

public class From
{
    public int ID { get; set; }
    public string Name { get; set; }
}
public class Message
{
    public int FromID { get; set; }
    public string Subject { get; set; }
    public DateTime SentDate { get; set; }
}
public class MetaMsg
{        
    public string FromName { get; set; }        
    public string Subject { get; set; }
    public DateTime SentDate { get; set; }
}

我想返回一个由From.Name, SubjectSentDate排序的10个Message对象的列表

我现在能做到这一点的唯一方法是从数据库中返回所有MessageFrom对象,并手动将它们组合成一个元对象,就像这样

List<MetaMsg> list = new List<MetaMsg>();
var froms = db.From.Where(//etc).ToList();
var messages = db.Message.Where(//bla bla).ToList();
foreach(Message m in messages)
{
    MetaMsg mm = new MetaMsg {
        Subject = m.Subject, 
        SentDate = m.SentDate
        FromName = froms.Where(f = f.ID == m.FromID).FirstOrDefault().Name
    };
    list.Add(mm);
}
if(//sort by subject)
{
    list = list.OrderBy(x => x.Subject).Take(10).ToList();        
}
else if(//sort by date)
{
    list = list.OrderBy(x => x.SentDate).Take(10).ToList();        
}
else
{
    list = list.OrderBy(x => x.FromName).Take(10).ToList();
}

是否有一种方法可以做到这一点,而不返回MessageFrom的完整列表?

<标题> 更新

这里有一个更好的解释,我想在弗兰肯代码中做什么(不完全是伪代码,也不是真正的代码)

List<MetaMsg> list = new List<MetaMsg>();
// get a list of 'From's, ordered by name
var froms = db.From.Where(//etc).OrderBy(x => x.Name);
var messages = null;
if(//sort by subject)
{
    // order by subject and take 10
    messages = db.Messages.OrderBy(x => x.Subject).Take(10).ToList();        
}
else if(//sort by date)
{        
   // order by date and take 10
    messages = db.Messages.OrderBy(x => x.Subject).Take(10).ToList();      
}
else // sort by from Name...
{
    // try and select 10 successive messages which have the fromID 
    // of our first (sorted) from on the list
    int i = 0;        
    while(messages.Count < 10)
    {
        // if i is greater than the number of items in from, stop!
        if(i > from.Count)
            break;
        
        messages += db.Messages.Where(x => x.FromID == from[i].ID).Take(10).ToList();
        // if we don't quite make 10, keep going with the next id
        i++;
    }
}
// now create our list of froms. 
foreach(Message m in messages)
{
    MetaMsg mm = new MetaMsg {
        Subject = m.Subject, 
        SentDate = m.SentDate
        FromName = froms.Where(f = f.ID == m.FromID).FirstOrDefault().Name
    };
    list.Add(mm);
}

这里的细微差别在于,第二个示例只选择了10个消息对象,而第一个示例必须选择所有消息对象才能按名称排序。

从技术上讲,我的第二个例子中的代码应该工作(我还没有尝试过),但我想知道是否有一个更优雅的方式做到这一点?

根据另一个IQueryable的值排序IQueryable

您可以像这样直接投影到MetaMsg:

var result = (from m in db.Messages
              let fromName = (from f in db.From
                              where m.FromId == f.ID                                  
                              select f.Name).FirstOrDefault()
              /* If you have navigation properties setup, you may be able to do this */
              let fromName = m.From.Name
              orderby fromName 
              select new MetaMsg
              {
                  Subject = m.Subject, 
                  SentDate = m.SentDate,
                  FromName = fromName,                      
              }).Take(10).ToList();