2010-05-30 53 views
0

我想弄清楚如何在LINQ中進行混合連接,並對2個LINQ對象進行特定的訪問。下面是實際的TSQL查詢可能外觀的示例:幫助LINQ:混合連接並指定默認值

SELECT 
    * 
FROM 
    [User] AS [a] 
INNER JOIN 
    [GroupUser] AS [b] 
ON 
    [a].[UserID] = [b].[UserID] 
INNER JOIN 
    [Group] AS [c] 
ON 
    [b].[GroupID] = [c].[GroupID] 
LEFT JOIN 
    [GroupEntries] AS [d] 
ON 
    [a].[GroupID] = [d].[GroupID] 
WHERE [a].[UserID] = @UserID 

最後,基本上是我想是一個枚舉對象全GroupEntry對象。什麼是感興趣的是這個查詢中的最後兩個表/對象。我將顯示組作爲組標題,以及組標題下的所有條目。如果組中沒有條目,我仍然希望將該組看作沒有任何條目的標題。這是我到目前爲止有:

所以從這一點我想提出一個功能:

public void DisplayEntriesByUser(int user_id) 
{ 
    MyDataContext db = new MyDataContext(); 

    IEnumberable<GroupEntries> entries = 
    (
     from user in db.Users 
     where user.UserID == user_id 
     join group_user in db.GroupUsers 
      on user.UserID = group_user.UserID 
     into a 

     from join1 in a 
     join group in db.Groups 
      on join1.GroupID equals group.GroupID 
     into b 

     from join2 in b 
     join entry in db.Entries.DefaultIfEmpty() 
      on join2.GroupID equals entry.GroupID 
     select entry 
    ); 


    Group last_group_id = 0; 
    foreach(GroupEntry entry in entries) 
    { 
     if (last_group_id == 0 || entry.GroupID != last_group_id) 
     { 
      last_group_id = entry.GroupID; 
      System.Console.WriteLine("---{0}---", entry.Group.GroupName.ToString().ToUpper()); 

     } 
     if (entry.EntryID) 
     { 
      System.Console.WriteLine(" {0}: {1}", entry.Title, entry.Text); 
     } 
    } 
} 

上面的例子並沒有完全達到預期效果。有2個問題,我一直沒能解決:

  1. 我似乎仍然得到一個INNER JOIN代替LEFT JOIN在最後加入。我沒有收到任何空的結果,所以沒有條目的組不會出現。

  2. 我需要找出一種方法,以便我可以填寫空白條目集的默認值。也就是說,如果有一個沒有條目的組,我希望返回一個大部分空白的條目,除了我希望EntryID爲null或0,GroupID是它所代表的空組的組,我需要一個處理entry.Group對象(即它是父對象,空Group對象)。

對此的任何幫助將不勝感激。

注意:表名和真實世界的表示法純粹是爲了這個例子而衍生的,但它們的關係簡化了我想要做的事情。

回答

0

這是未經測試,但我認爲這是相當接近:

var groupEntries = 
    from 
     u in db.Users 
    where 
     user.Id == user_id 
    join 
     gu in db.GroupUsers 
     on u.UserId equals gu.UserId 
    join 
     g in db.Groups 
     on gu.GroupId equals g.GroupId 
    join 
     ge in db.GroupEntries 
     on u.GroupdId equals ge.GroupId 
     into ges 
    from 
     ge in ges.DefaultIfEmpty(new GroupEntry { EntryId = 0, GroupId = g.GroupId }) 
    select 
     ge; 

我不認爲你需要使用into,除非你打算做一些進一步的處理,如DefaultIfEmpty()。並注意第二個超載DefaultIfEmpty()允許您輸入自定義的默認值。因此,您可以創建一個新的GroupEntry對象,併爲每個屬性分配所需的值(或將屬性留空)。

+0

非常感謝丹。這是一個更直接的查詢。後面的代碼稍後會陷入一些麻煩。我當前的函數需要一個IEnumberable 對象類型,通過它可以迭代。現在,在我的foreach循環中,在查詢之後,我得到了「用於查詢運算符'DefaultEmpty'的不支持的重載」錯誤。 在好奇心相關的一面,如果你在linq中使用「into」關鍵字,它是否必須在下面的db層創建一個子查詢? – 2010-05-30 17:04:19

+0

Corey,這是一個LinqToSql查詢嗎? – devuxer 2010-05-30 21:52:28

+0

Yessir。底層數據庫是MSSQL 2005服務器。 – 2010-05-30 22:43:41

0
//set this to see all queries issued. 
myDC.Log = Console.Out; 

    //setup to load the GroupEntries property of each group 
DataLoadOptions o = new DataLoadOptions(); 
o.LoadWith<Group>(g => g.GroupEntries); 
myDC.LoadOptions = o; 

    //query to get the groups 
IQueryable<Group> groupQuery = 
    from g in myDC.Groups 
    where g.GroupUsers.Any(gu => gu.User.UserID == user_id) 
    select g; 
+0

嗨大衛。關於最後兩節,我必須承認這略高於我的理解。你在這裏使用匿名函數(lambda表達式)?您是否願意快速解釋這裏發生的事情,或者可能有助於解釋的快速鏈接?提前致謝。 – 2010-06-01 17:23:00