2009-11-05 88 views
0

我的查詢是:例外的LINQ to SQL

var ReadAndUnreadMessages = 
     (from m in MDB.Messages 
     orderby m.Date descending 
     where m.ID_Receive == (Guid)USER.ProviderUserKey && m.Delete_Admin == false 
     select new AllMessages() 
     { 
      id = (LoadMessageChildren(m.ID_Message)[LoadMessageChildren(m.ID_Message).Count - 1] as Message).ID_Message, 
      parent = (Guid)(LoadMessageChildren(m.ID_Message)[LoadMessageChildren(m.ID_Message).Count - 1] as Message).ID_Message_Parent, 
      sender = (LoadMessageChildren(m.ID_Message)[LoadMessageChildren(m.ID_Message).Count - 1] as Message).ID_Sender, 
      receiver = (Guid)USER.ProviderUserKey, 
      subject = (LoadMessageChildren(m.ID_Message)[LoadMessageChildren(m.ID_Message).Count - 1] as Message).Subject.Subject1.ToString() == "Other" ? 
          (LoadMessageChildren(m.ID_Message)[LoadMessageChildren(m.ID_Message).Count - 1] as Message).Other_Subject 
          : 
          (LoadMessageChildren(m.ID_Message)[LoadMessageChildren(m.ID_Message).Count - 1] as Message).Subject.Subject1.ToString(), 
      body = (LoadMessageChildren(m.ID_Message)[LoadMessageChildren(m.ID_Message).Count - 1] as Message).Body.Length > 26 ? 
        (LoadMessageChildren(m.ID_Message)[LoadMessageChildren(m.ID_Message).Count - 1] as Message).Body.Substring(0, 25) + "..." 
        : 
        (LoadMessageChildren(m.ID_Message)[LoadMessageChildren(m.ID_Message).Count - 1] as Message).Body, 
      date = (LoadMessageChildren(m.ID_Message)[LoadMessageChildren(m.ID_Message).Count - 1] as Message).Date.ToShortDateString(), 
      read =(LoadMessageChildren(m.ID_Message)[LoadMessageChildren(m.ID_Message).Count - 1] as Message).IsRead, 
      finished = (LoadMessageChildren(m.ID_Message)[LoadMessageChildren(m.ID_Message).Count - 1] as Message).IsFinished, 
      count = MessageClass.LoadAll(m.ID_Message).Count 
     }).ToList(); 

和例外是:

參數 '價值' 是錯誤的類型。預期'消息'。實際的'System.Object'。

什麼意思呢?

LoadMessageChildren:

public static ArrayList LoadMessageChildren(Guid Parent) 
{ 
    ArrayList arr = new ArrayList(); 
    Guid id = Parent; 
    while (id != Guid.Empty) 
    { 
     arr.Add(LoadMessage(id)); 
     try 
     { 
      id = (Guid)MDB.Messages.Single(a => a.ID_Message_Parent == id).ID_Message; 
     } 
     catch 
     { 
      id = Guid.Empty; 
     } 
    } 
    return arr; 
} 

LoadMessage:

public static Message LoadMessage(Guid id) 
{ 
    var mess = from m in MDB.Messages 
       where m.ID_Message == id 
       select m; 

    return mess.Single(); 
} 
+0

什麼是您的數據類。 – 2009-11-05 18:07:42

+0

每件事情都可以,我做班級資料並寫下這個查詢,我只給你發送一部分代碼。 – 2009-11-05 18:11:52

+0

你可以發佈LoadMessageChildren函數嗎?錯誤可能在那裏,甚至在其中一個屬性設置器中。你有堆棧跟蹤顯示錯誤在這裏? – Kobi 2009-11-09 13:45:47

回答

5

的代碼無法讀取,並作爲代碼重複(和LoadMessageChildren多個執行)不好的情況下。
對於初學者來說,考慮以下因素:

from m in MDB.Messages 
    orderby m.Date descending 
    where m.ID_Receive == (Guid)USER.ProviderUserKey && m.Delete_Admin == false 
    let children = LoadMessageChildren(m.ID_Message) 
    let lastChildMessage = children.Last() 
    select new AllMessages() 
    { 
     id = lastChildMessage.ID_Message, 
     ... 
    } 

這可能會解決你的問題,因爲它是might be caused by using the [] indexer
除此之外,發佈的代碼不會導致異常。

+0

LodMessageChildren方法返回一個ArrayList – 2009-11-10 19:19:03

+0

在這種情況下,您可以執行'let children = LoadMessageChildren(m.ID_Message).Cast ()'。 ArrayLists與linq並不搭配,因爲它們是無類型的,但它是可行的。如果可能,嘗試運行'var messages = LoadMessageChildren(m.ID_Message).Cast ().ToList();'。如果這不起作用,這是你的問題的原因。 – Kobi 2009-11-10 19:43:07

+0

我嘗試了這個例外:「在'System.Collections.ArrayList'和'Message'類型之間沒有定義強制操作符。」 – 2009-11-11 15:36:17

0

錯誤很可能是由於使用ArrayList而造成的。

問題是,LINQ被設計爲使用實現System.Collections.Generic.IEnumerable<T>接口的通用集合。 ArrayList是一個非專有集合,它在內部將所有內容存儲爲Object。所以當你從ArrayList中獲取某些東西時,你需要將它轉換爲Message。 看看您的錯誤消息,它看起來像某個Message對象是預期的,但是ArrayList(Object)中的實例在該參考發生時未被轉換爲Message對象。此外,ArrayList不實現IEnumerable<T>接口,這也可能讓你在某些情況下遇到麻煩。

如何解決?

我建議改變你LoadMessageChildren的方案中使用generic listList<Message>):

public static List<Message> LoadMessageChildren(Guid Parent) 
{ 
    List<Message> arr = new List<Message>(); 
    Guid id = Parent; 
    while (id != Guid.Empty) 
    { 
     arr.Add(LoadMessage(id)); 
     try 
     { 
      id = (Guid)MDB.Messages.Single(a => a.ID_Message_Parent == id).ID_Message; 
     } 
     catch 
     { 
      id = Guid.Empty; 
     } 
    } 
    return arr; 
} 

你將不得不作出同樣改變與泛型列表中檢索/參照項目方面交互的代碼。但這只是語法。因爲存在處理列表和項目的等價方法。

在從ArrayList切換到List<T>時,在性能和編譯時驗證方面也有優勢。 ArrayList基本上是從.Net Framework 1.0版繼承而來,當它不支持泛型時,它可能出於兼容性的原因被保留在框架中。 還有更大的benefits for using generics

修訂答:

的 「法 'System.Collections.Generic.List'1 [信息] LoadMessageChildren(的System.Guid)' 有沒有支持轉換爲SQL」 例外,你因爲您的LoadMessageChildren方法沒有映射到數據庫中的存儲過程或用戶定義的函數而引起的。

在LINQ to SQL查詢中不能有任何常規的C#方法調用。 LINQ to SQL object model將在查詢中發現的方法解釋爲存儲過程或用戶定義的函數。所以引擎基本上正在尋找一種名爲LoadMessageChildren的方法,該方法映射到數據庫中的存儲過程或用戶定義的函數。由於沒有映射,它會告訴您找到no supported translation to SQL。鏈接LINQ to SQL object model顯示如何使用方法屬性來映射執行存儲過程的方法。

您有幾種選擇現在:

  1. 創建常規C#方法的存儲過程調用
  2. 重寫LINQ查詢中使用joins選擇孩子的消息
+0

出現此異常: 方法'System.Collections.Generic.List'1 [消息] LoadMessageChildren(System.Guid)'不支持對SQL的轉換。 – 2009-11-14 12:11:57

+0

查看我更新的答案。 – 2009-11-15 17:37:14

0

我唯一最後看到你使用LoadChildMessages()來得到子消息數量......除非我錯了,我認爲你可以把它寫成一個連接。您在查詢中執行了很多查詢,這些查詢看起來並不必要,並且可能會導致多次訪問數據庫。我對這個問題是爲什麼沒有在你的DMBL/SQL數據庫中的關係,使LinqToSql知道要創建一個屬性爲List<Message> ChildMessages

但這裏是我的看法:

var query = from message in MDB.Messges 
      join childmessage in MDB.Messages.Where(child => child.ID_Message_Parent == message.ID_Message) into childMessages 
      from childMessage in childMessages.DefaultIfEmpty() // This creates a 
      // left outer join so you get parent messages that don't have any children 
      where message.ID_Receive == (Guid)USER.ProviderUserKey && message.Delete_Admin == false 
      select new AllMessages() 
      { 
       id = message.ID_Message, 
       parent = message.ID_Message_Parent, 
       sender = message.ID_Sender, 
       receiver = (Guid)USER.ProviderUserKey, 
       subject = message.Subject.Subject1.ToString() == "Other" ? 
          message.Other_Subject 
          : 
          message.Subject.Subject1.ToString(), 
       body = message.Body.Length > 26 ? 
        message.Body.Substring(0, 25) + "..." 
        : 
        message.Body, 
       date = message.Date.ToShortDateString(), 
       read =message.IsRead, 
       finished = message.IsFinished, 
       count = childMessage.Count() // This might have to be this 
       //count = childMessage == null ? 0 : childMessage.Count() 
      }; 

var ReadAndUnreadMessages = query.ToList(); 

但很難說因爲我不能運行代碼...請回應,讓我知道這是否工作。

注意:我可以建議使用一個鏈接到您的DataContext.Log屬性的類,它將生成的TSQL代碼寫入調試器窗口。這裏有一篇關於writing your own的文章。當我對數據庫進行不必要的調用時,它確實幫助我知道。