我有一条这样的SQL语句:
SELECT
projects.name, projects.id,
issues.subject, issues.description,
time_entries.spent_on, time_entries.hours
FROM
(time_entries
INNER JOIN
projects ON time_entries.project_id = projects.id)
INNER JOIN
issues ON time_entries.issue_id = issues.id
WHERE
(((projects.id) IN (26, 27))
AND ((issues.subject) NOT LIKE "*zlecane*"))
AND MONTH(spent_on) = MONTH(CURRENT_TIMESTAMP)
GROUP BY
name, id, subject, spent_on
我需要用Linq编写。
我这样写,但是不起作用-它返回一个空列表:
ProjectIdsForBudgets-列出了26和27
Projects.Include(x => x.Issues)
.ThenInclude(k => k.TimeEntries)
.Where(x => ProjectIdsForBudgets.Contains(x.Id) &&
x.Issues.Any(y => !y.Subject.Contains("zlecane") &&
y.TimeEntries.Any(K => K.SpentOn >= firstDayOfTheMonth)
)
)
我们可以跳过分组方式
你能帮我吗?
答案 0 :(得分:0)
在SQL查询中,您不能选择不属于组或聚合函数的字段。您可能是说SUM(time_entries.hours)
,但我不知道。这是最有效的文字翻译。
var result = from time in time_entries
join issue in issues on time.issue_id equals issue.id
join project in projects on time.project_id equals project.id
where (new int[] { 26, 27 }).Contains(project.id)
&& !issue.subject.Contains("zlecane")
&& time.spent_on.Split('-')[1] == DateTime.Now.ToString("MM")
group time by new
{
projectName = project.name,
projectId = project.id,
issueSubject = issue.subject,
issueDescription = issue.description,
timeSpentOn = time.spent_on
} into g
select new
{
projectName = g.Key.projectName,
projectId = g.Key.projectId,
issueSubject = g.Key.issueSubject,
issueDescription = g.Key.issueDescription,
timeSpentOn = g.Key.timeSpentOn,
timeHours = g.Sum(e=>e.hours)
};
答案 1 :(得分:0)
因此,您有一个Projects
序列和一个Issues
序列。此外,您有一个TimeEntries
序列,其中每个TimeEntry
使用外键Project
恰好属于一个TimeEntry.ProjectId
。每个TimeEntry
也使用外键Issue
恰好属于一个TimeEntry.IssueId
您要在这三个表的主键和外键上联接。您只想保留合并结果的某些元素(位置)。其余元素应使用相同的name
,id
,subject
和spentOn
分组。最后,您要从每个组及其元素中选择一些属性。
如果您具有类似于实体框架的内容,则您的项目将有一个虚拟的TimeEntries集合,并且每个TimeEntry都有一个对项目的虚拟引用。如果使用该方法,则实体框架将理解需要联接。您可以在表之间使用引用。
稍后将讨论。首先使用联接三个表的方法
通常我会使用Method语法。但是method syntax looks hideous if you join three tables.是我唯一使用查询语法的时间。
我以较小的步骤执行此操作。随意将它设为大衬里
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);
将结果元素分组为相同的[名称,ID,主题,花spent]:
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,
...
});