2015-09-02 48 views
0

我有兩個從Linq返回到SQL的IQueryables,我想按照另一個排序。從本質上講,這是我基於另一個IQueryable的值排序IQueryable

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.NameSubjectSentDate

分類我現在可以這樣做的權利的唯一途徑10個Message對象的列表是返回所有Message並從數據庫和手動From對象結合他們的元對象,像這樣

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

UPDATE

這裏是什麼,我想在弗蘭肯代碼做一個更好的解釋(這是不是很僞代碼,不是很真實代碼)

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個消息對象,其中第一個例子必須選擇所有這些對象以便按名稱排序。

從技術上講,我的第二個例子中的代碼應該可以工作(我還沒有嘗試過),但我想知道是否有更優雅的方式來做到這一點?

+0

您至少可以使用'Join'來創建元對象,這將至少搬東西出來'的O(N^2) '範圍。實際上,如果您想通過'From.Name'來訂購,您應該只需要這樣做;否則'Message'本身就有信息。 –

回答

1

您可以直接投射到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(); 
+0

這隻適用於按主題或日期排序。我想通過'FromName'進行訂購,而無需首先返回整組消息 – roryok

+0

@ roryok - 對不起,我更新了答案。這將被轉換爲SQL,它不會返回整個消息集 – Aducci