嵌套MySQL查询的解决方法?

时间:2014-12-11 08:35:19

标签: c# mysql entity-framework

以下代码段是伪的 - 数据库结构没有任何问题。我正在使用Database First方法,它们已经证明可以正常工作。

考虑以下表格;

public class Blog
{
    public int Id { get; set; }
    public string Content { get; set; }
    public ICollection<Post> Posts { get; set; }
}

public class Post
{
    public string UserName { get; set; }
    public int BlogId { get; set; }
    public string Content { get; set; }
    public virtual Blog Blog { get; set; }       
}

并说我想抓住用户已发布两次(或更多)的所有Blogs。 考虑到MyDbContextDbContext,我会这样做;

using(var context = new MyDbContext)
{
    var doublePosters = context.Blog.Where(b => b.Posts.GroupBy(p => p.UserName).Any(x => x.Count() > 1));
    foreach(var poster in doublePosters)
    {
        //Do things with it
    }
}

反过来,由于我使用的是EF6和MySQL数据库,IQueryable<>将如下所示;

SELECT `Extent1`.`Id`, `Extent1`.`Content` 
FROM `Blog` AS `Extent1`
WHERE EXISTS
(
    SELECT 1 AS `C1`
    FROM 
        (
        SELECT
        `Extent2`.`UserName` AS `K1`, COUNT(1) AS `A1`
        FROM `Post` AS `Extent2`
        WHERE `Extent1`.`Id` = `Extent2`.`BlogId`
        GROUP BY `Extent2`.`UserName`
        ) AS `GroupBy1`
    WHERE `GroupBy1`.`A1` > 1
 )

然而,MySQL不能很好地处理这个问题,因为它返回

  

SQL错误(1054):'where子句'

中的未知列'Extent1.Id'

我已经认为这是MySQL的限制,因此我的问题是如何在不严格打击数据库的情况下实现相同的结果?

当然,一个选项是查询整个Blog表,将其放在List<>中,让LINQ完成其余的工作。但是,我的Blog表包含~500000条记录 - 不是所有的好主意。

修改

一些样本数据和预期数据;

博客:

+----+---------+
| Id | Content |
+----+---------+
| 1  | "blabla"|
| 2  | "albalb"|
+----+---------+

发表:

+--------+----------+---------+
| BlogId | UserName | Content |
+--------+----------+---------+
| 1      |  Jon     | "Nice!" |
| 1      |  Jon     | "Well.."|
| 1      |  Jon     | "Nvm."  |
| 1      |  Sam     | "Ok!"   |
| 1      |  Sam     | "Good." |
| 1      |  Robert  | "Sweet" |
| 2      |  Robert  | "Nah"   |
| 2      |  Jonah   | "Hey"   |
+--------+----------+---------+

查询的预期输出:

+----+---------+
| Id | Content |
+----+---------+
| 1  | "blabla"|
+----+---------+

由于只有Blog 1张贴了多次发贴的海报(看着你,Jon和Sam)。

1 个答案:

答案 0 :(得分:1)

这种方法怎么样(将查询拆分为两部分)?

var posts= context.Posts.GroupBy(p => p.UserName).Any(x => x.Count() > 1).Select(y=>y.BlogId).ToList(); 
var doublePosters = context.Blog.Where(b=> posts.Contains(b.Id)); 
foreach(var poster in doublePosters) {
            //Do things with it 
}

我不确定这种方法的性能(代码未经过测试),也许它可能是解决问题的新方法的起点。

我建议的是

  1. 获取博客的所有ID,其中有人发布了多次。
  2. 按上一个查询的ID筛选博客
  3. <强>更新

    尝试此代码以实现您的目标

    var postIds = context.Posts.GroupBy(p => new {p.BlogId,p.UserName}).Where(x=> x.Count() > 1).Select(el=> el.Key.BlogId);
    var doublePosters = context.Blog.Where(b => postIds.Contains(b.Id)).ToList();
    

    关键是按BlogId和UserName分组