views:

293

answers:

5

This is my query:

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) 

Currently the Join is not left join, meaning if some forum doesn't have a post that belongs to it, it will not be returned.
The forum without posts must be returned with null (or default) values for the post properties.

UPDATE

The result set should be some thing like that:

ForumId | ForumTitle | LastPostTitle | LastPostAddedDate  
--------+------------+---------------+------------------
4       |   Sport    |    blabla     |       12/4/2010  
4       |   Sport    |    blabla     |       15/4/2010  
6       |   Games    |    blabla     |       1/5/2010  
7       |   Flame    |               |
A: 
 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
chugh97
this doesn't do what i need
shivesh
When I get allForums, I check if count of post = 0, then I print No Posts else I print all the posts for the Forum. Is that what you want???
chugh97
Why don't you use the join clause? The result set is not the one that i want, your's returns 'forum' and all it's posts. But I want to return forums per post (JOIN)!
shivesh
You cannot use the join syntax in Linq to Entities ..It is not same as LINQ to SQL, so this query produces a LEFT OUTER JOIN behind the hood if you look thru SQL Profiler
chugh97
Can you give me an example output of what the result should look like
chugh97
I've updated the question
shivesh
see updated answer: Added a DisplaySet class which is how your final result will look like
chugh97
A: 
 var allforums = from f in context.Fora.Include("Posts")
                           select f;

This query produces the same results as

            var allForums = from f in context.Fora  
                            select new ForumPosts  
                            {  
                                Forum = f,  
                                Posts = context.Posts.Where(x=> x.ForumId == f.ForumId)  
chugh97
yes, and how this helps me?
shivesh
A: 

Here is some code to help you to work out Left Join with Link

    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);
        }
    }
davidwatercamp
DefaultIfEmpty() is not supported by Entity framework in Net 3.5
shivesh
A: 
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,
    });

Something similar to this. I wasn't too sure because I didn't really have a view of the data model, but GroupJoin should be very similar to LEFT OUTER JOIN even though it doesn't realistically produce that in SQL.

jwendl
A: 

Try something like this:

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)

properties that return empty from the left join must also be nullable. So int => int? and DateTime => DateTime? etc..

Andre Haverdings