英文:
How do I write a LINQ query for a list of users with their first article?
问题
Here's the LINQ query that corresponds to the provided SQL query:
var query =
from u in db.Users
join a in db.Articles on u.Id equals a.UserId
group new { u.Id, u.Username, a.Id, a.CreatedAt } by u.Id into g
orderby g.Key
select new
{
UserId = g.Key,
Username = g.First().Username,
FirstArticleId = g.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id).First().Id,
FirstArticleCreatedAt = g.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id).First().CreatedAt
};
This query should provide the desired result, grouping by the UserId
and selecting the additional fields Username
, FirstArticleId
, and FirstArticleCreatedAt
for each user's first article.
英文:
How do I write a LINQ query that would translate to the following SQL?
SELECT u.id, u.username, a.id, MIN(a.created_at) AS firstArticle
FROM users u
INNER JOIN editorial_articles a
ON a.user_id = u.id
GROUP BY u.id
ORDER BY u.id, a.created_at, a.id
Basically, a list of users with their first article.
Everything that I try results in an incorrect group-by clause (too many columns), not enough columns selected, or some other issue.
I've tried a thousand different combinations – why is this so difficult?
Classes:
[Table("users")]
public class User
{
[Column("id", IsPrimaryKey = true, IsIdentity = true, SkipOnInsert = true, SkipOnUpdate = true)]
public int Id { get; set; } // int
[Column("username", CanBeNull = false)]
public string Username { get; set; } = null!; // varchar(20)
[Association(ThisKey = nameof(Id), OtherKey = nameof(Article.UserId))]
public IEnumerable<Article> Articles { get; set; } = null!;
}
[Table("articles")]
public class Article
{
[Column("id", IsPrimaryKey = true, IsIdentity = true, SkipOnInsert = true, SkipOnUpdate = true)]
public int Id { get; set; } // int
[Column("user_id")]
public int UserId { get; set; } // int
[Column("created_at")]
public DateTime CreatedAt { get; set; } // datetime
[Association(CanBeNull = false, ThisKey = nameof(UserId), OtherKey = nameof(User.Id))]
public User User { get; set; } = null!;
}
Update:
The closest that I get with a GROUP BY is:
var result =
from user in db.Users
join article in db.Articles
on user.Id equals article.UserId into articles
from article in articles
group article by new { user } into g
orderby g.Key.user.Id, g.Min(a => a.CreatedAt), g.Min(a => a.Id)
select new
{
User = g.Key,
FirstArticle = g.Min(a => a.CreatedAt)
};
I don't like that it puts all of the user fields into the group-by. If you just group by Id
, then it's not possible to reference the initial user
in the select.
Is there no way to group by ID, but select additional fields?
答案1
得分: 2
使用窗口函数 ROW_NUMBER
来执行这个任务:
var query =
from u in db.Users
from a in u.Articles
select new
{
User = u,
FirstArticle = a,
RN = Sql.Ext.RowNumber().Over()
.PartitionBy(u.Id)
.OrderBy(a.CreatedAt)
.ToValue()
} into s
where s.RN == 1
select new
{
s.User,
s.FirstArticle
};
英文:
Use Window Function ROW_NUMBER
for such task:
var query =
from u in db.Users
from a in u.Articles
select new
{
User = u,
FirstArticle = a,
RN = Sql.Ext.RowNumber().Over()
.PartitionBy(u.Id)
.OrderBy(a.CreatedAt)
.ToValue()
} into s
where s.RN == 1
select new
{
s.User,
s.FirstArticle
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论