所以你有一个Projects 序列和一个Issues 序列。此外,您还有一系列TimeEntries,其中每个TimeEntry 使用外键TimeEntry.ProjectId 恰好属于一个Project。每个TimeEntry 也恰好属于一个Issue,使用外键TimeEntry.IssueId
您希望将这三个表的主键和外键连接起来。您只想保留连接结果的某些元素(位置)。其余元素应分组为具有相同name、id、subject 和spentOn 的组。最后,您想从每个组及其元素中选择一些属性。
如果你有类似实体框架的东西,你的项目将有一个 TimeEntries 的虚拟集合,每个 TimeEntry 都有一个对项目的虚拟引用。如果使用该方法,实体框架将理解需要连接。您可以使用表之间的引用。
这将在稍后讨论。首先使用连接三表的方法
方法:连接三张表
通常我会使用方法语法。但是method syntax looks hideous if you join three tables. 这些是我唯一使用查询语法的时候。
我以较小的步骤进行此操作。随意把它变成一个大 linq
var joinedItems = from timeEntry in timeEntries
join project in project on timeEntry.ProjectId equals project.Id
join issue in issues on timeEntry.IssueId equals issue.Id
select new
{
TimeEntry = timeEntry,
Project = Project,
Issue = Issue,
};
只保留部分连接项:
int currentMonth = DateTime.Now.Month;
var subsetJoinedItems = joinedItems.Where(joinedItem =>
(joinedItem.Project.Id == 26 || joinedItem.Project.Id == 27)
&& joinedItem.Issue.Subject.Contains("zlecane") // consider ignore case
&& joinedItem.TimeEntry.SpentOn.Month == currentMonth);
将生成的元素分组为相同的 [name、id、subject、spend_on] 组:
var groups = subsetJoinedItems.GroupBy(joinedItem => new
{
ProjectId = joinedItem.Project.Id,
ProjectName = joinedItem.Project.Name,
Subject = joinedItem.Issue.Subject,
Spent_on = joinedItem.TimeEntry.SpentOn,
});
最后,从每个组中选择您要保留的项目:
var result = groups.Select(group => new
{
ProjectId = group.Key.ProjectId,
ProjectName = group.Key.ProjectName,
Subject = group.Key.Subject,
SpentOn = group.Key.SpentOn,
// remaining properties: SQL query seems incorrect
...
});
在实体框架中使用类关系
如果您有类似于实体框架的东西,那么您的一对多关系将使用集合来实现:
class TimeEntry
{
public int Id {get; set;}
// every TimeEntry belongs to exactly one Project using foreign key
public int ProjectId {get; set;}
public virtual Project Project {get; set;}
// every TimeEntry belongs to exactly one Issue using foreign key
public int IssueId {get; set;}
public virtual Issue Issue {get; set;}
}
如果你有这样的东西,你不必自己做连接,实体框架会理解它:
var result = TimeEntries.Where(timeEntry =>
(timeEntry.ProjectId == 26 || timeEntry.ProjectId == 27)
&& timeEntry.Issue.Subject.Contains("zlecane") // consider ignore case
&& TimeEntry.SpentOn.Month == currentMonth)
.GroupBy(timeEntry => new
{
ProjectId = joinedItem.Project.Id,
ProjectName = joinedItem.Project.Name,
Subject = joinedItem.Issue.Subject,
Spent_on = joinedItem.TimeEntry.SpentOn,
})
.Select(group => new
{
ProjectId = group.Key.ProjectId,
ProjectName = group.Key.ProjectName,
Subject = group.Key.Subject,
SpentOn = group.Key.SpentOn,
...
});