2010-05-05 21 views
7

Dies ist meine Frage:Linq to Entities LEFT JOIN

from forum in Forums 
    join post in Posts on forum equals post.Forum into postGroup  

    from p in postGroup  
    where p.ParentPostID==0 

    select new 
    { 
     forum.Title, 
     forum.ForumID, 
     LastPostTitle = p.Title, 
     LastPostAddedDate = p.AddedDate   
    }).OrderBy(o=>o.ForumID) 

die Zeit Registriert wird kommen nicht verlassen, was bedeutet, wenn einige Forum nicht einen Beitrag hat, die ihm gehört, wird es nicht zurückgeschickt .
Das Forum ohne Posts muss mit Null (oder Standardwerten) für die Post-Eigenschaften zurückgegeben werden.

UPDATE

Die Ergebnismenge soetwas wie das sein sollte:

ForumId | ForumTitle | LastPostTitle | LastPostAddedDate 
--------+------------+---------------+------------------ 
4  | Sport | blabla  |  12/4/2010 
4  | Sport | blabla  |  15/4/2010 
6  | Games | blabla  |  1/5/2010 
7  | Flame |    | 
+0

Ihre 'von p in postGroup' sollte' von p in postGroup.DefualtIfEmpty() ' –

Antwort

0
public class ForumPosts 
    { 
     public Forum Forum { get; set; } 
     public IQueryable<Post> Posts { get; set; } 
    } 

    public class DisplaySet 
    { 
     public string Name { get; set; } 
     public string PostTile { get; set; } 
    } 



      //left outer join 
      using (ClassLibrary1.Entities context = new Entities()) 
      { 
       var allForums = from f in context.Fora 
           select new ForumPosts 
           { 
            Forum = f, 
            Posts = context.Posts.Where(x=> x.ForumId == f.ForumId) 

           }; 
       List<DisplaySet> ds = new List<DisplaySet>(); 

       foreach (var forum in allForums) 
       { 
        if (forum.Posts.AsEnumerable().Count() != 0) 
        { 
         foreach (var post in forum.Posts) 
         { 
          ds.Add(new DisplaySet(){ Name = forum.Forum.Name, PostTile = post.PostValue}); 
         } 
        } 
        else 
         ds.Add(new DisplaySet(){ Name = forum.Forum.Name, PostTile = string.Empty}); 
       } 

       foreach (var item in ds) 
       { 
        Console.WriteLine(string.Format("{0} || {1}",item.Name,item.PostTile)); 
       } 


      } 



//This produces the following LINQ query which is right 
SELECT 
[Project1].[ForumId] AS [ForumId], 
[Project1].[Name] AS [Name], 
[Project1].[C1] AS [C1], 
[Project1].[PostId] AS [PostId], 
[Project1].[PostValue] AS [PostValue], 
[Project1].[ForumId1] AS [ForumId1] 
FROM (SELECT 
    [Extent1].[ForumId] AS [ForumId], 
    [Extent1].[Name] AS [Name], 
    [Extent2].[PostId] AS [PostId], 
    [Extent2].[PostValue] AS [PostValue], 
    [Extent2].[ForumId] AS [ForumId1], 
    CASE WHEN ([Extent2].[PostId] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1] 
    FROM [dbo].[Forum] AS [Extent1] 
    LEFT OUTER JOIN [dbo].[Post] AS [Extent2] ON [Extent2].[ForumId] = [Extent1].[ForumId] 
) AS [Project1] 
ORDER BY [Project1].[ForumId] ASC, [Project1].[C1] ASC 
+0

das tut nicht, was ich brauche – shivesh

+0

Wenn ich allForums bekomme, überprüfe ich, ob die Anzahl der Post = 0, dann drucke ich keine Posts sonst drucke ich alle Beiträge für das Forum. Ist es das was du willst??? – chugh97

+0

Warum verwenden Sie nicht die Join-Klausel? Die Ergebnismenge ist nicht die, die ich möchte, Ihr 'Forum' und alle seine Beiträge. Aber ich möchte Foren per Post (JOIN) zurückgeben! – shivesh

1
var allforums = from f in context.Fora.Include("Posts") 
          select f; 

Diese Abfrage zu denselben Ergebnissen wie

  var allForums = from f in context.Fora 
          select new ForumPosts 
          { 
           Forum = f, 
           Posts = context.Posts.Where(x=> x.ForumId == f.ForumId) 
+0

ja, und wie hilft mir das? – shivesh

1

Hier ist ein Code, Ihnen zu helfen, mit Link zu trainieren LEFT JOIN

private class EntityRole 
    { 
     public int EntityId { get; set; } 
     public int RoleId { get; set; } 
    } 

    private IList<EntityRole> GetSourceEntityRole() 
    { 
     var list = new List<EntityRole>() {new EntityRole(){EntityId = 123, RoleId = 1}, 
              new EntityRole(){EntityId = 123, RoleId = 2}, 
              new EntityRole(){EntityId = 123, RoleId = 3}, 
              new EntityRole(){EntityId = 123, RoleId = 4}}; 

     list.Reverse(); 

     return list; 
    } 

    private IList<EntityRole> GetEmptyEntityRole() 
    { 
     var list = new List<EntityRole>(); 

     return list; 
    } 

    public void TestToDelete() 
    { 
     var source = this.GetSourceEntityRole(); 
     var destination = this.GetEmptyEntityRole(); 

     this.TestLeftJoin(source, destination); 
    } 

    private void TestLeftJoin(IList<EntityRole> source, IList<EntityRole> destination) 
    { 
     var inserting = this.GetMissing(source, destination); 
     var deleting = this.GetMissing(destination, source); 

     this.Enumerate("Source", source); 
     this.Enumerate("Destination", destination); 

     this.Enumerate("Deleting", deleting); 
     this.Enumerate("Inserting", inserting); 
    } 

    private IEnumerable<EntityRole> GetMissing(IList<EntityRole> sourceEntities, IList<EntityRole> destinationEntities) 
    { 
     return from source in sourceEntities 
       join dest in destinationEntities on source.RoleId equals dest.RoleId into joined 
       from source2 in joined.DefaultIfEmpty() 
       where source2 == null 
       select source; 
    } 

    private void Enumerate(string source, IEnumerable<EntityRole> roles) 
    { 
     foreach (var item in roles) 
     { 
      Console.WriteLine("{0}:{1}", source, item.RoleId); 
     } 
    } 
+1

DefaultIfEmpty() wird nicht unterstützt von Entity-Framework in Net 3.5 – shivesh

+0

Ich würde gerne Code sehen, der Linke Verbindung mit Zelda hilft;) –

1
Forums 
    .GroupJoin(PostGroup, f => f.ID, p => p.ForumID, (f, p) => new { Forum = f, PostList = p }) 
    .Where(anon => anon.PostList.Any(pl => pl.ParentPostID.Equals(0))) 
    .OrderBy(anon => anon.Forum.ForumID) 
    .Select(anon => new 
    { 
     Title = anon.Forum.Title, 
     ForumID = anon.Forum.ForumID, 
     LastPostTitle = anon.PostList.FirstOrDefault().Title, 
     LastPostAddedDate = anon.PostList.FirstOrDefault().AddedDate, 
    }); 

Etwas ähnlich. Ich war mir nicht sicher, weil ich nicht wirklich eine Sicht auf das Datenmodell hatte, aber GroupJoin sollte LEFT OUTER JOIN sehr ähnlich sein, obwohl es das in SQL nicht realistisch erzeugt.

1

versuchen, etwas wie folgt aus:

from forum in Forums 
join post in Posts on forum equals post.Forum into postGroup  

// from p in postGroup  
// where p.ParentPostID==0 

select new 
{ 
    forum.Title, 
    forum.ForumID, 
    LastPostTitle = postGroup.FirstOrDefault(p => p.ParentPostID==0).Title, 
    LastPostAddedDate = (DateTime?)postGroup.FirstOrDefault(p => p.ParentPostID==0).AddedDate   
}).OrderBy(o=>o.ForumID) 

Eigenschaften, die von der linken Seite leer zurückkehren kommen auch nullable sein muss. Also int => int? und DateTime => DateTime? etc ..

1

wenn nicht Fehler:

var list = from forum in Forums.DefaultItIfEmpty() 
from post in Posts.DefaultItIfEmpty() 
where forum.forum_id == post.forum_id && post.ParentPostID==0 
select new 
{ 
    forum.Title, 
    forum.ForumID, 
    LastPostTitle = p.Title, 
    LastPostAddedDate = p.AddedDate   
}).OrderBy(o=>o.ForumID) 
1

Haben Sie versucht, so etwas wie:

from forum in Forums 
from posts in (Posts.Where(qPosts=> forum.ForumId == qPosts.ForumId)).DefaultIfEmpty() 
where posts.ParentPostID == 0 
orderby forum.ForumId 
select new 
{ 
    forum.Title, 
    forum.ForumID, 
    LastPostTitle = posts.Title, 
    LastPostAddedDate = posts.AddedDate 
}