Linq,linq在哪里在哪里

时间:2018-06-23 13:39:57

标签: c# .net linq entity-framework-core

我有一条这样的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)
              )
         )

我们可以跳过分组方式

你能帮我吗?

2 个答案:

答案 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

您要在这三个表的主键和外键上联接。您只想保留合并结果的某些元素(位置)。其余元素应使用相同的nameidsubjectspentOn分组。最后,您要从每个组及其元素中选择一些属性。

如果您具有类似于实体框架的内容,则您的项目将有一个虚拟的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,
        ...
     });