Trying to type a Linq expression that will include information from two tables.
var articles = db.Articles;
var articlescores = db.ArticleScores;
articles table has the title field
articles.title
the articlescores table has the ActualCity field and ArticleID field
articlescores.ActualCity
artickescores.ArticleID (which links to articles table)
I need to .Count()
the articlescores.ActualCity
field, then store the highest counted city in a string along with articles.title
Basically articles viewed most by a city.
Sample Data:
ArticleScore table:
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
article table:
ID title
1 TitleOneOfArticles
2 TitleTwoOfArticles
Expected output (because New York has a count of 4, Boston only has 2):
TitleOneOfArticles, NewYork(4)
^^ ^^ ^
title City Count
Only one line of output is expected.
Your question is self-contradictory and it's also missing some key information. So I'm going to take a guess.
Here is how I understand a sample ArticleScore dataset:
ID articleID City
? 1 New York
? 1 New York
? 1 New York
? 1 Boston
? 2 New York
? 2 Boston
? 2 Boston
In this dataset there are 3 views for article 1 in NewYork and 1 view of article 2. Likewise, in Boston, there are 2 views of article 2 and 1 view of article 1.
Based on this data, I'm assuming you want to get something like this
TitleTwoOfArticles, Boston(2)
TitleOneOfArticles, NewYork(3)
This table above signifies that In Boston the most viewed article is article 2 with the total of 2 views. In NewYork, the most viewed article is 1 with the total of 3 view. Note that the total number of views for an article across all cities is not shown here.
A created a code sample to test the scenario above, for it I used:
Here is the code:
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();
}
}
}
The linq queries that is of most interest to you are in the main method. Modify the connection string to point to your test server. Make sure that the database name you are using DOES NOT EXIST because database with this name WILL BE DROPPED. Be careful.
When the program runs it drops/creates the specified database and creates the sample schema in it. The it proceeds inserting its sample data, as described above. Then the actual query you are interested in follow.
I split the query to three parts. Firstly, we group by city name and article id and calculate counts for each line. Secondly, we select only those lines that have maximum count number for each city. Finally, we join with the Article table to get article title from the id.
After that we print out the results. It should be easy to modify the query to return just one line, you just need to add a condition to it.
try this 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)
the cityId is parameter that you should send
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.