【问题标题】:How to get most frequently repeated object in a n-n relationship?如何在 n-n 关系中获得最频繁重复的对象?
【发布时间】:2016-10-06 09:41:44
【问题描述】:

我有这 2 个实体(在 C# 和 EntityFramework 中):

public class Article 
{ 
    public int Id { get; set; }
    public IList<Tag> Tags { get; set; }
}

public class Tag 
{
    public int Id { get; set; }
    public IList<Article> Articles { get; set; }
}

有 n-n 关系。我正在加载我的文章,就像你在这个 sn-p 中看到的那样简单:

var model = _context.Articles
                    .AsNoTracking()
                    .Include(a => a.Tags)
                    .ToList();

现在,我正在尝试获取Tags,这在此 sn-p 的文章中重复次数最多:

var tags = model.SelectMany(a => a.Tags)
                .GroupBy(t => new { t.Name, t.Articles })
                .OrderByDescending(g => g.Count())
                .Take(10);

但它似乎不起作用(我得到所有标签的 Count = 1)。我在这里想念什么?请问有什么想法吗?提前致谢。

【问题讨论】:

    标签: c# asp.net-mvc entity-framework c#-4.0 entity-framework-6


    【解决方案1】:

    回答您的具体问题:

    但它似乎不起作用(我得到所有标签的 Count = 1)。我在这里错过了什么?

    这是因为您已将tag.Articles 包含在分组键中。通常,如果具有相同IdTag 对象共享同一个实例,则不会有问题(除了冗余和不必要的比较)。但是,由于您使用不使用跟踪查询 (.AsNoTracking()) 填充了 model,因此表示同一记录的 Tag 对象实际上是不同的实例(数据重复),它们的 Articles 列表也是如此,因此group by 没有按预期工作。通过下面的sn-p可以很容易看出:

    foreach (var tagGroup in model.SelectMany(a => a.Tags).GroupBy(t => t.Id))
    {
        Tag prevTag = null;
        foreach (var tag in tagGroup)
        {
            if (prevTag != null) Debug.Assert(prevTag == tag); // FAIL!
            prevTag = tag;
        }
    }
    

    要解决此问题,请从分组键中删除 AsNotracking 或排除 Articles

    var tags = model.SelectMany(a => a.Tags)
                    .GroupBy(t => t.Id) // or Name
                    .OrderByDescending(g => g.Count())
                    .Take(10);
    

    【讨论】:

      【解决方案2】:

      如果您感兴趣的是Articles by Tags 那么为什么不选择相反的方式:

      var model = _context.Tags.AsNoTracking()
                          .Include(t => t.Articles)
                          .OrderByDescending(t => t.Articles.Count())
                          .Take(10)
                          .ToList();
      

      【讨论】:

        【解决方案3】:

        作为对 Gilad Green 答案的一个小补充,这是一个填充样本集的小程序,然后选择文章中出现最多的前 100 个标签

        class Program
        {
            public class Article
            {
                public Article()
                {
                    Tags = new HashSet<Tag>();
                }
        
                public int Id { get; set; }
                public HashSet<Tag> Tags { get; set; }
            }
        
            public class Tag
            {
                public Tag()
                {
                    Articles = new HashSet<Article>();
                }
        
                public int Id { get; set; }
                public HashSet<Article> Articles { get; set; }
            }
        
            static void Main(string[] args)
            {
        
                List<Article> articles = new List<Article>();
                List<Tag> tags = new List<Tag>();
        
                int n = 100;
        
                for (int i = 0; i < n; i++)
                {
                    tags.Add(new Tag() { Id = i });
                }
        
                int v = 100;
        
                Random rnd = new Random();
        
                for (int i = 0; i < v; i++)
                {
                    var article = new Article() { Id = i };
        
                    int c = rnd.Next(1,v);
        
                    for (int k = 0; k < c; k++)
                    {
                        var tag = tags[rnd.Next(0, v - 1)];
        
                        article.Tags.Add(tag);
                        tag.Articles.Add(article);
                    }
        
                    articles.Add(article);
                }
        
        
                var orderedbyarticles = tags.OrderBy(x => x.Articles.Count).Take(100).ToList();
        
                foreach(var item in orderedbyarticles)
                {
                    System.Console.WriteLine(item.Id);    
                }
        
                System.Console.ReadLine();
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-11-11
          • 1970-01-01
          • 1970-01-01
          • 2020-12-14
          • 2020-09-20
          • 1970-01-01
          • 2011-10-05
          相关资源
          最近更新 更多