在实体框架中使用不同或不相等的左连接

时间:2014-06-26 00:40:23

标签: asp.net sql-server entity-framework linq-to-entities left-join

我必须构建一个查询来获取未收到的用户并提醒新帖子。

我的相关表格结构如下:

帖子:postId int 用户:userId int,email varchar PostAlertUsers:postAlertUserId int,postId int,userId int

所有相关字段在表之间都有FK约束。

我在SQL中构建了这个查询,但找不到在Entity Framework中工作的方法:

SELECT u.email
FROM Users u
INNER JOIN Posts p ON p.userId != u.userId 
LEFT JOIN PostAlertUsers pu ON u.userId = pu.userId AND p.postId = pu.postId 
WHERE pu.postAlertUserId IS NULL

我写了以下EF查询,但没有得到相同的结果:

from u in context.Users
join pu in context.PostAlertUsers on u.userId equals pu.userId into postAlerts
from pa in postAlerts.DefaultIfEmpty()
join p in context.Posts on pa.postId equals p.postId
where pa.userId != u.userId
select u.email;

如何使用linq实体获得相同的结果。使用点语法(我不知道DbSet.Where(x => ...)语法的正确术语)会更好。

修改

我希望PostAlertUsersPost的{​​{1}}内没有Posts的记录的所有用户都不是来自同一用户。

编辑2:

试图澄清一点:

我想警告用户每个帖子只有一次来自其他用户的新帖子,我的例程会每小时运行一次,检查是否有人发送消息。

我想让所有尚未收到有关帖子警告的用户因此在PostAlertUsers上没有该用户和帖子组合的记录,但会在其他用户的帖子上有记录

示例数据:

Users
------------------------
userid | email
------------------------
1      | email1@test.com
2      | email2@test.com
3      | email3@test.com
------------------------

Posts (posts are created by users)
------------------------
postId | userId
------------------------
1      | 1
2      | 3
3      | 1
------------------------

PostAlertUsers (every time a user is notified about a new post, one record is added here)
------------------------
postId | userId
------------------------
1      | 2
1      | 3
2      | 1
------------------------

生成的查询将输出以下数据:

Result (using postId and userId to identify what user have to be notified for what post)
---------------------------------
postId | userId | email
---------------------------------
2      | 2      | email2@test.com
3      | 2      | email2@test.com
3      | 3      | email3@test.com
---------------------------------

修改

感谢AD.Net,我提出了以下建议:

from u in context.Users
let posts = contexto.Posts.Where(p => p.userId != u.userId)
from p in posts
join pau in context.PostAlertUsers on u.userId equals pau.userId 
into alerts
from a in alerts.DefaultIfEmpty()
where a == null || a.postId != p.postId
orderby p.idPost
select new {
    p.postId,
    u.userId,
    u.email
}

1 个答案:

答案 0 :(得分:1)

编辑: 从不同角度进行的另一次尝试,不确定性能,可能与cross-join

一样糟糕
       from p in context.Posts
       let otherUsers = context.Users.Where(u => u.UserId != p.User.UserId)
       from u in otherUsers
       join pau in alerts on u.UserId equals pau.User.UserId into alert
       from a in alert.DefaultIfEmpty()
       where a == null || a.Post.PostId != p.PostId
       select new {p.PostId, u.Email};

这是LinqPad的尝试:

void Main()
{
     var users = new List<User>{new User{UserId = 1}, new User{UserId = 2}};
            var posts = new List<Post>
            {
                new Post{PostId = 1, User = new User{UserId = 2}},
                new Post{PostId = 2, User = new User{UserId = 1}},
                new Post{PostId = 3, User = new User{UserId = 2}},
            };
            var alerts = new List<PostUserAlert>
            {
                new PostUserAlert{Post = new Post{PostId = 1}, 
                                    User = new User{UserId = 1}}
            };

            var result = (from p in posts
                let otherUsers = users.Where(u => u.UserId != p.User.UserId)
                from u in otherUsers
                join pau in alerts on u.UserId equals pau.User.UserId into alert
                from a in alert.DefaultIfEmpty()
                where a == null || a.Post.PostId != p.PostId
                select new {p.PostId, u.UserId}).ToList();

                result.Dump();
}


 class User
    {
        public int UserId { get; set; }
        public string Email { get; set; }
    }

    class Post
    {
        public int PostId { get; set; }
        public User User { get; set; }

        public List<PostUserAlert>  PostUserAlerts { get; set; }
    }

    class PostUserAlert
    {
        public Post Post { get; set; }
        public User User { get; set; }
    }
// Define other methods and classes here