Ho una dichiarazione SQL come questa:
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
e ho bisogno di scriverlo in Linq.
Lo scrivo così ma non funziona - restituisce una lista vuota:
ProjectIdsForBudgets - è una lista con 26 e 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)
)
)
Group by possiamo saltare
Mi potete aiutare per favore?
Quindi hai una sequenza di Projects
e una sequenza di Issues
. Inoltre, hai una sequenza di TimeEntries
cui ogni TimeEntry
appartiene esattamente a un Project
utilizzando la chiave TimeEntry.ProjectId
. Ogni TimeEntry
appartiene anche a esattamente un Issue
utilizzando la chiave TimeEntry.IssueId
Vuoi unirti a queste tre tabelle sulle loro chiavi primarie e straniere. Si desidera conservare solo alcuni elementi dei risultati uniti (Dove). Gli elementi rimanenti dovrebbero essere raggruppati in gruppi con lo stesso name
, id
, subject
e spentOn
. Infine, vuoi selezionare alcune proprietà da ogni gruppo con i suoi elementi.
Se si dispone di qualcosa di simile all'entità framework, il progetto avrà una collezione virtuale di TimeEntries e ogni TimeEntry ha un riferimento virtuale a un progetto. Se viene utilizzato quel metodo, il framework delle entità comprenderà che è necessario un join. Puoi utilizzare i riferimenti tra i tavoli.
Questo è discusso più tardi. Innanzitutto il metodo che utilizza le tre tabelle join
Normalmente userei la sintassi del metodo. Tuttavia la sintassi del metodo appare orribile se si uniscono tre tabelle. Quelle sono le uniche volte in cui utilizzo la sintassi Query.
Lo faccio a piccoli passi. Sentiti libero di fare un grande 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,
};
Mantieni solo alcuni degli elementi uniti:
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);
Raggruppa gli elementi risultanti in gruppi di stessi [nome, id, oggetto, spent_on]:
var groups = subsetJoinedItems.GroupBy(joinedItem => new
{
ProjectId = joinedItem.Project.Id,
ProjectName = joinedItem.Project.Name,
Subject = joinedItem.Issue.Subject,
Spent_on = joinedItem.TimeEntry.SpentOn,
});
Infine, da ogni gruppo seleziona gli oggetti che vuoi mantenere:
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
...
});
Se si dispone di qualcosa di simile al framework entità, le relazioni uno-a-molti sarebbero state implementate utilizzando le raccolte:
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;}
}
Se hai qualcosa del genere, non devi fare da solo le join, l'entity framework lo capirebbe:
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,
...
});