我有两个表:
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(。我决定给你的表起一些有意义的名字,这样讨论就更容易了。
Articles
和ArticleTypes
之间存在一对多关系:每个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(),
});
})