我有一个示例数据库,其中包含电影、人员和演职员表。电影表包含标题和ID,人员表包含名称和ID。演职员表将参与电影制作的人员与电影及其所扮演角色相关联。该表格如下:
在这个简单的例子中,[Role] 列是一个单字符,按照我的惯例,要么是 'A' 表示该人在特定电影中是演员,要么是 'D' 表示导演。
我想对某个人执行查询,返回该人的姓名,以及该人参与过的所有电影和电影中的角色列表。
如果我将其序列化为 json,则可能如下所示:
我收到了这样的信息:
输出结果与我所需的相当接近。它看起来像这样:
CREATE TABLE [dbo].[Credits] (
[Id] [int] IDENTITY (1, 1) NOT NULL PRIMARY KEY,
[PersonId] [int] NOT NULL FOREIGN KEY REFERENCES People(Id),
[MovieId] [int] NOT NULL FOREIGN KEY REFERENCES Movies(Id),
[Role] [char] (1) NULL
在这个简单的例子中,[Role] 列是一个单字符,按照我的惯例,要么是 'A' 表示该人在特定电影中是演员,要么是 'D' 表示导演。
我想对某个人执行查询,返回该人的姓名,以及该人参与过的所有电影和电影中的角色列表。
如果我将其序列化为 json,则可能如下所示:
{
"name" : "Clint Eastwood",
"movies" : [
{ "title": "Unforgiven", "roles": ["actor", "director"] },
{ "title": "Sands of Iwo Jima", "roles": ["director"] },
{ "title": "Dirty Harry", "roles": ["actor"] },
...
]
}
如何编写一个 LINQ-to-SQL 查询以使输出呈现这样的形式?
我正在努力高效地完成它。
尝试 #1
如果我使用这个查询:
int personId = 10007;
var persons =
from p in db.People
where p.Id == personId
select new
{
name = p.Name,
movies =
(from m in db.Movies
join c in db.Credits on m.Id equals c.MovieId
where (c.PersonId == personId)
select new {
title = m.Title,
role = (c.Role=="D"?"director":"actor")
})
};
我收到了这样的信息:
{
"name" : "Clint Eastwood",
"movies" : [
{ "title": "Unforgiven", "role": "actor" },
{ "title": "Unforgiven", "role": "director" },
{ "title": "Sands of Iwo Jima", "role": "director" },
{ "title": "Dirty Harry", "role": "actor" },
...
]
}
这并不完全正确。您可以看到,每个由Eastwood扮演多个角色的电影都有一个副本。我预计这是因为在该电影+人物组合的credits表中有多行记录,每行记录代表一个角色。
尝试 #2
我想使用group by来实现,就像这样:
var persons =
from p in db.People
where p.Id == personId
select new
{
name = p.Name,
movies =
(from m in db.Movies
join c in db.Credits on m.Id equals c.MovieId
where (c.PersonId == personId)
orderby m.Year
group ((c.Role == "A")? "actor":"director")
by m.Id
into g
select new {roles = g })
};
输出结果与我所需的相当接近。它看起来像这样:
{
"name" : "Clint Eastwood",
"movies" : [
{ "roles": ["actor", "director"]},
{ "roles": ["director"]},
{ "roles": ["actor"]},
...
]
}
接近了,但是我没有电影标题。
尝试 #3
如果我使用group by并包含电影标题,就像这样:
var persons =
from p in db.People
where p.Id == personId
select new
{
name = p.Name,
movies =
(from m in db.Movies
join c in db.Credits on m.Id equals c.MovieId
where (c.PersonId == personId)
orderby m.Year
group ((c.Role == "A")? "actor":"director")
by m.Id
into g
select new { title = m.Title, roles = g })
};
如果出现以下错误,则无法编译:
error CS0103: 当前上下文中不存在名称'm'
我该如何按照自己的意愿塑造输出结果?
Person
列但是应该有一个Person
关联。当你通过这个关联进行分组时,它知道如何在翻译成SQL时使用关联列 (PersonId
)。如果数据库中有FK,则自动创建关联。你可以将表拖到设计器中(这正是我在这里所做的)。实际上,我从测试项目中直接复制和粘贴了这段代码。如果你缺少关联,那么你会让自己的生活变得更加困难... - Aaronaught