从主表中选择所有列,从JOINed表中只选择一列



我有两个表:

Table1
Id         ArticleName      ArticleTypeId
1          Blah Blah        3
2          Helo Blah        5

Table2
ArticleTypeId       TypeName
3                   Business
5                   Construction

我试图在ArticleTypeId上连接表A和表B,基本上从表1返回所有内容,从表2 返回TypeName

以下是我要做的,但我不确定是否要编辑语句中的SELECT以包含TypeName

var articles = (from s in _context.Articles
join b in _context.ArticleTypes on s.ArticleTypeId equals b.ArticleTypeId
select s).ToList();

或者有更简单的方法吗?

目标:

Id      ArticleName      TypeName
1       Blah Blah        Business
2       Helo Blah        Construction

因此您有两个表,一个表带有Articles(表1(,另一个表具有ArticleTypes(表2(。我决定给你的表起一些有意义的名字,这样讨论就更容易了。

ArticlesArticleTypes之间存在一对多关系:每个Article都有一个ArticleType,即外键ArticleTypeId所指的Article类型。每个ArticleType都有零个或多个引用它的Article。

您正在使用实体框架。如果您已经遵循了实体框架编码约定,那么您将拥有与以下类似的类。

class Article
{
public int Id {get; set;}
public string Name {get; set;}
// every Article has one ArticleType, namely the one that the foreign key refers to
public int ArticleTypeId {get; set;}
public virtual ArticleType ArticleType {get; set;}
}
class ArticleType
{
public int Id {get; set;}
public string TypeName {get; set;}
// every ArticleType has zero or more Articles referring to it (one-to-many)
public virtual ICollection<Article> Articles {get; set;}
}

在实体框架中,非虚拟属性指的是表的列;虚拟属性是指表之间的关系(一对多、多对多…(

外键ArticleTypeId是实列,因此该属性是非虚拟的。属性ArticleType是虚拟的,因为它表示一对多关系。

为了完整性,您的DbContext:

class MyWarehouse : DbContext
{
public DbSet<Article> Articles {get; set;}
public DbSet<ArticleType> ArticleTypes {get; set;}
}

我正在尝试在ArticleTypeId上连接表A和表B,并基本上从表1返回所有内容,从表2 返回TypeName

定义了类之后,查询就很容易了。最简单的方法是使用虚拟属性。

使用虚拟属性

要求给我所有物品的Id和名称,每个物品都有其TypeName。

using (var wareHouse = new MyWareHouse(...))
{
var requestedArticles = wareHouse.Articles.Select(article => new
{
// Select only the Article Properties that you plan to use
Id = article.Id,
Name = article.Name,
TypeName = article.ArticleType.TypeName,
});
// Process the requested Articles before disposing the wareHouse
}

换句话说:从文章表中的每一篇文章中提取Id、Name和它所拥有的唯一TypeName。

实体框架知道文章和文章类型之间的关系。因为您使用虚拟属性Article.ArticleType,所以它知道要执行哪个联接。

使用虚拟属性,您还可以将每个ArticleType与具有此ArticleTypes 的所有文章放在一起

var constructionArticles = wareHouse.ArticleTypes
.Where(articleType => articleType.TypeName == "construction")
.Select(articleType => new
{
Id = articleType.Id,
TypeName = articleType.TypeName,
// fetch all articles that have this TypeName
Articles = articleType.Articles.Select(article => new
{
Id = article.Id,
Name = article.Name,
// no need to fetch the foreign key, you already got this value
// ArticleTypeId = article.ArticleTypeId,
})
.ToList(),
})
.ToList();

实体框架知道这种关系,并将为您进行适当的(Group-(加入。

你注意到使用虚拟财产的感觉有多自然吗?

自己加入

有些人不想使用虚拟属性,他们更喜欢自己加入(Group-(。

使用具有参数resultSelector的方法Join的重载,以便指定所需的结果。

// Join Articles with ArticleTypes
var requestedArticles = wareHouse.Articles.Join(wareHouse.ArticleTypes,
// from every Article take the foreign key
article => articleTypeId,
// from every ArticleType take the primary key
articleType => articleType.Id,
// parameter resultSelector:
// take each article and its one and only matching ArticleType to make one new
(article, articleType) => new
{
Id = article.Id,
Name = article.Name
TypeName = articleType.TypeName,
});

如果您有一对多关系,如学校与学生、客户与订单或文章类型与文章,请使用GroupJoin并从"一"端开始。如果你想要"学生",请使用"加入",并从"多"方开始。

var schoolsWithTheirStudents = dbContext.Schools
.Where(school => school.City == ...)     // if you don't want all Schools
.GroupJoin(dbContext.Students,
// from every School take the primary key
school => school.Id,
// from every Student take the foreign key to the School he attends
student => student.SchoolId,
// resultSelector: take each Schools with its matching Students to make one ned
(school, studentsWhoAttendThisSchool) => new
{
// Select only the School properties that you plan to use:
Id = school.Id,
Name = school.Name,
Address = school.Address,
...
// studentsWhoAttendThisSchool is a queryable sequence,
// so you can use LINQ on it:
Students = studentsWhoAttendThisSchool.Select(student => new
{
Id = student.Id,
Name = student.Name,
...
})
.ToList(),
});
})

最新更新