Как мне наиболее элегантно выразить левое соединение с помощью aggregate SQL в виде запроса LINQ
Вопрос
SQL:
SELECT
u.id,
u.name,
isnull(MAX(h.dateCol), '1900-01-01') dateColWithDefault
FROM universe u
LEFT JOIN history h
ON u.id=h.id
AND h.dateCol<GETDATE()-1
GROUP BY u.Id, u.name
Решение
Решением, хотя и таким, которое откладывает обработку нулевого значения в коде, могло бы быть:
Дата-время вчера = Дата-время.Сейчас.Дата.Добавленные дни(-1);
var collection=
from u in db.Universe
select new
{
u.id,
u.name,
MaxDate =(DateTime?)
(
from h in db.History
where u.Id == h.Id
&& h.dateCol < yesterday
select h.dateCol
).Max()
};
Это не приводит к точно такому же SQL, но обеспечивает тот же логический результат.Перевод "сложных" SQL-запросов в LINQ не всегда прост.
Другие советы
var collection=
from u in db.Universe
select new
{
u.id,
u.name,
MaxDate =(DateTime?)
(
from h in db.History
where u.Id == h.Id
&& h.dateCol < yesterday
select h.dateCol
).Max()
};
Просто используйте приведенный выше код, и это должно сработать нормально!
Это не полный ответ для вас, но в левой части соединения вы можете использовать оператор DefaultIfEmpty следующим образом:
var collection =
from u in db.Universe
join history in db.History on u.id = history.id into temp
from h in temp.DefaultIfEmpty()
where h.dateCol < DateTime.Now.Date.AddDays(-1)
select u.id, u.name, h.dateCol ?? '1900-01-01'
У меня еще не было необходимости выполнять какие-либо команды groupby, поэтому я опустил это, чтобы не направить вас по ложному пути.Следует отметить еще две быстрые вещи.Мне не удалось фактически объединить два параметра, хотя, как указано выше, есть способы обойти это.Кроме того, этот??operator действительно хорошо работает вместо isnull в SQL.
Вы наверняка захотите использовать join into
сконструируйте для создания группового запроса.
TestContext db = new TestContext(CreateSparqlTripleStore());
var q = from a in db.Album
join t in db.Track on a.Name equals t.AlbumName into tracks
select new Album{Name = a.Name, Tracks = tracks};
foreach(var album in q){
Console.WriteLine(album.Name);
foreach (Track track in album.Tracks)
{
Console.WriteLine(track.Title);
}
}