Linq查询多个表

时间:2014-04-08 05:19:01

标签: c# linq asp.net-mvc-4

尝试键入包含两个表中信息的Linq表达式。

        var articles = db.Articles;
        var articlescores = db.ArticleScores;

文章表有标题字段

articles.title

articlescores表具有ActualCity字段和ArticleID字段

articlescores.ActualCity
artickescores.ArticleID (which links to articles table)

我需要.Count() articlescores.ActualCity字段,然后将最高计数的城市与articles.title

一起存储在一个字符串中

基本上是一个城市观看的文章。

示例数据:

ArticleScore表:

    ID articleID City  (Note: articleID is not dependent on City, I just wrote it this way)
    1    1       New York   
    2    2       Boston
    3    1       New York
    4    1       New York
    5    1       New York
    6    2       Boston

文章表:

ID title
1  TitleOneOfArticles
2  TitleTwoOfArticles

预期输出(因为纽约有4个,波士顿只有2个):

TitleOneOfArticles, NewYork(4)
      ^^              ^^     ^
    title            City   Count

预计只有一行输出。

2 个答案:

答案 0 :(得分:3)

你的问题是自相矛盾的,而且它也缺少一些关键信息。所以我要猜一猜。

  • 你没有提到你正在使用的linq。您使用的是Entity Framework吗?光速?别的什么?我假设它的实体框架
  • 你说你需要基本上由城市观看的文章,但是你继续前进并给出一些不同的例子。
  • ,我将假设它是城市中观看次数最多的文章
  • 您说articleID不依赖于City,但后来举例说明了City和articleID之间的一对一关系。

以下是我对ArticleScore数据集示例的理解:

    ID articleID  City  
     ?    1       New York   
     ?    1       New York
     ?    1       New York
     ?    1       Boston
     ?    2       New York
     ?    2       Boston
     ?    2       Boston

在这个数据集中,NewYork的第1条有3个视图,第2条有1个视图。同样,在波士顿,有2篇关于第2条的视图和1条关于第1条的视图。

根据这些数据,我假设你想得到类似的东西

TitleTwoOfArticles, Boston(2)
TitleOneOfArticles, NewYork(3)

上表显示在波士顿,观看次数最多的文章是第2条,总共有2个观看次数。在NewYork,观看次数最多的文章是1,总共3个视图。请注意,此处未显示所有城市中文章的总观看次数。

创建了一个代码示例来测试上面的场景,因为我使用了它:

  • Visual Studio 2013 / .net 4.5
  • 实体框架6

以下是代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;

namespace SO22928136
{
    public interface IMyDbContext : IDisposable
    {
        IDbSet<Article> Articles { get; set; }
        IDbSet<ArticleScore> ArticleScores { get; set; }
        int SaveChanges();
    }

    public class MyDbContext : DbContext, IMyDbContext
    {
        public IDbSet<Article> Articles { get; set; }
        public IDbSet<ArticleScore> ArticleScores { get; set; }

        static MyDbContext()
        {
            Database.SetInitializer(new DropCreateDatabaseAlways<MyDbContext>());
        }

        public MyDbContext(string connectionString) : base(connectionString)
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Configurations.Add(new ArticleConfiguration());
            modelBuilder.Configurations.Add(new ArticleScoreConfiguration());
        }
    }

    public class Article
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public virtual ICollection<ArticleScore> ArticleScores { get; set; }
        public Article()
        {
            ArticleScores = new List<ArticleScore>();
        }
    }

    public class ArticleScore
    {
        public int Id { get; set; }
        public int ArticleId { get; set; }
        public string ActualCity { get; set; }
        public virtual Article Article { get; set; }
    }

    internal class ArticleConfiguration : EntityTypeConfiguration<Article>
    {
        public ArticleConfiguration()
        {
            ToTable("Article");
            HasKey(x => x.Id);
            Property(x => x.Id).HasColumnName("Id").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            Property(x => x.Title).HasColumnName("Title").IsOptional();
        }
    }

    internal class ArticleScoreConfiguration : EntityTypeConfiguration<ArticleScore>
    {
        public ArticleScoreConfiguration()
        {
            ToTable("ArticleScore");
            HasKey(x => x.Id);
            Property(x => x.Id).HasColumnName("Id").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            Property(x => x.ArticleId).HasColumnName("ArticleId").IsRequired();
            Property(x => x.ActualCity).HasColumnName("ActualCity").IsOptional().HasMaxLength(10);
            HasRequired(a => a.Article).WithMany(b => b.ArticleScores).HasForeignKey(c => c.ArticleId);
        }
    }


    class Program
    {
        static void Main()
        {
            MyDbContext context = new MyDbContext("Data Source=(local);Initial Catalog=SO22928136;Integrated Security=True;");
            CreateTestData(context);

            var countOfArticlesPerCity = context.ArticleScores.GroupBy(s => new {s.ArticleId, s.ActualCity}).Select(g => new {g.Key.ArticleId, g.Key.ActualCity, Count = g.Count()});
            var highestArticleCountPerCity = countOfArticlesPerCity.GroupBy(x => x.ActualCity).Select(g => g.OrderByDescending(x => x.Count).FirstOrDefault());
            var highestArticleCountPerCityWithArticleTitle = context.Articles.Join(highestArticleCountPerCity, x => x.Id, p => p.ArticleId, (x, p) => new { x.Title, p.ActualCity, p.Count });

            foreach (var line in highestArticleCountPerCityWithArticleTitle)
            {
                Console.WriteLine("{0}, {1}({2})",line.Title,line.ActualCity, line.Count);
            }

        }

        private static void CreateTestData(MyDbContext context)
        {
            Article articleOne = new Article { Title = "TitleOneOfArticles" };
            Article articleTwo = new Article { Title = "TitleTwoOfArticles" };

            articleOne.ArticleScores.Add(new ArticleScore { ActualCity = "NewYork" });
            articleOne.ArticleScores.Add(new ArticleScore { ActualCity = "NewYork" });
            articleOne.ArticleScores.Add(new ArticleScore { ActualCity = "NewYork" });
            articleOne.ArticleScores.Add(new ArticleScore { ActualCity = "Boston" });

            articleTwo.ArticleScores.Add(new ArticleScore { ActualCity = "NewYork" });
            articleTwo.ArticleScores.Add(new ArticleScore { ActualCity = "Boston" });
            articleTwo.ArticleScores.Add(new ArticleScore { ActualCity = "Boston" });

            context.Articles.Add(articleOne);
            context.Articles.Add(articleTwo);
            context.SaveChanges();
        }
    }
}

您最感兴趣的linq查询是主要方法。修改连接字符串以指向测试服务器。确保您使用的数据库名称不存在,因为具有此名称的数据库将被删除。小心。

程序运行时,它会删除/创建指定的数据库并在其中创建示例模式。如上所述,它继续插入其样本数据。然后是您感兴趣的实际查询。

我将查询分为三部分。首先,我们按城市名称和文章ID进行分组,并计算每行的计数。其次,我们只选择每个城市拥有最大计数的那些行。最后,我们加入Article表,从id获取文章标题。

之后我们打印出结果。应该很容易修改查询只返回一行,你只需要为它添加一个条件。

答案 1 :(得分:-1)

试试这个linq:

db.Articles
               .Join(db.ArticleScores ,
                   art=> art.ID,
                   scr=> scr.ID,
                   (art, scr) => new { article= art, score= scr})
                   .Where(both => (both.art.ID == cityID))
                   .Select(both => both.score)

cityId是您应该发送的参数