简体   繁体   English

Linq-to-Entities离开JOIN

[英]Linq-to-Entities Left JOIN

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. 目前,Join不是左连接,这意味着如果某个论坛没有属于它的帖子,则不会返回。
The forum without posts must be returned with null (or default) values for the post properties. 没有帖子的论坛必须返回post属性的null(或默认)值。

UPDATE 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    |               |

if not mistake: 如果没有错误:

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)

Did you try something like: 你尝试过这样的事情:

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
}
 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)  

Here is some code to help you to work out Left Join with Link 这里有一些代码可以帮助您解决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);
        }
    }
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. 我不太确定,因为我没有真正的数据模型视图,但GroupJoin应该与LEFT OUTER JOIN非常相似,即使它在SQL中没有实际产生。

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? 那么int => int? and DateTime => DateTime? 和DateTime => DateTime? etc.. 等等..

 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM