Join v LINQ   zodpovězená otázka

SQL, LINQ

Prosím vás, jak zapíšu takový dotaz v LINQu ?

select * from TrafficInformations  right join
(select  FK_JsdiId,Max(Version)as Ver from TrafficInformations where ValidFrom < SYSDATETIME() and ValidTo > SYSDATETIME()  group by FK_JsdiId) Sub
on Sub.FK_JsdiId=TrafficInformations.FK_JsdiId and TrafficInformations.Version=Sub.Ver;

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Tak asi vyřešeno:

(from t in db.TrafficInformations
where t.ValidFrom < now && t.ValidTo > now
group t.Version by t.FK_JsdiId into g
join tr in db.TrafficInformations
on new { ID = g.Key, Version = g.Max() } equals new { ID = tr.FK_JsdiId, Version = tr.Version }
select tr).Include(l => l.Location);
nahlásit spamnahlásit spam 0 odpovědětodpovědět

Jo, to by mělo fungovat, akorát bych prověřil to Include na konci, podle mě se ignoruje, pokud tam máte Select. Zkuste v debuggeru, jestli se ta lokace dotáhne hned, nebo jestli se dotahuje až separátními dotazy poté, co zpracováváte ty TrafficInformations.

Dal bych ten Include hned za db.TrafficInformations na prvním řádku, ale nejsem si jistý, vyzkoušejte to.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Pravě,když ten Include byl hned na prvním řádku, tak to nešlo, takhle to funguje správně.

Hned pod tím dotazem je

return dotaz.ToList();

a končí using blok, takže na lazy loading už by nebyl přístupný context.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Tak v tom případě je to OK, kdoví, jak to ta SQL-like syntaxe převádí.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Tak nakonec to správně nefunguje, chyba byla už v prvotním SQL dotazu, ten se nakonec zjednodušil na:

select  Id,FK_JsdiId,Version from TrafficInformations
where ValidFrom < SYSDATETIME() and  ValidTo > SYSDATETIME()
group by FK_JsdiId,Version,Id;

Snažím se ho přepsat do LINQ:

var query = from t in db.TrafficInformations
            where t.ValidFrom < now && t.ValidTo > now && t.Type == type
            group t by new { t.FK_JsdiId, t.Version, t.Id } into g
            select new BasicInfo
            {
              TrafficInformationId = t.Id,
              Lat = t.Location.Coord.Latitude,
              Long = t.Location.Coord.Longitude,
              LocationText = t.Location.Name,
              EventClassId = t.TMC.EventInfoes.Where(e => e.EventOrder == 1).FirstOrDefault().FK_UpdateClassId
             };

Ale nejsem schopný se dostat k objektu TrafficInformations "t" abych si mohl poskládat objekt BasicInfo.

V tom groupu se dostanu jen k těm hodnotám podle kterých se groupuje, jenže já potřebuju plnohodnotný objekt "t" abych se mohl přes něj dotazovat do dalších tabulek.

Metoda g.ToList() se tváří jakože by měla vrátit list TrafficInformation objektů, ale jak to zapsat v rámci jednoho dotazu?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

No pozor, přesně to, co se snažíte, udělat nejde a ani nemůže jít - v té skupince je třeba 10 objektů TrafficInformations a groupujete je podle dvou sloupců, což je ten klíč, ale nemůžete se jen tak dostat ke konkrétnímu objektu TrafficInformation, protože je jich tam 10 a neví se, který přesně chcete - hodnoty v ostatních sloupcích mohou být různé.

Jediné, co můžete udělat, je říct, že chcete Location z libovolného (prvního, který najdete) objektu t, pak můžete napsat g.FirstOrDefault().Location.Name, nebo že chcete třeba objekt s nejnižším Id, pak napíšete g.OrderBy(x => x.Id).FirstOrDefault().Location.Name, ale vždycky tam musíte mít nějaké pravidlo, kterým ten objekt t z té skupinky dostanete, protože je jich tam víc a mohou se něčím lišit. Ale většinou bývá lepší před tím udělat select, a tu Location.Name dát jako jedno z kritérií do GroupBy, protože pokud berete libovolný objekt z té skupiny, pak jsou v tom sloupci typicky stejné hodnoty (jinak by to vracelo náhodné výsledky, což asi nechcete), takže to klidně může být v tom group by.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

No já právě potřebuju celou tu skupinku. Celý ten group by je tam jen kvůli tomu abych dostal dopravní informaci s největší verzí, tedy tu nejaktuálnější. V tabulce jsou sice časy platí: od do, ale může nastat situace, kdy vyjde aktualizace s vyšší verzí, ale podle času může ještě platit informace i s verzí-1.

Zatím jsem to vyřešil joinem, který mi tu skupinku spojí s plnohodnotnými objekty podle Id:

   var query = from t in db.TrafficInformations
               where t.ValidFrom < now && t.ValidTo > now && t.Type == type
               group t by new { t.FK_JsdiId, t.Version, t.Id } into g
               join tr in db.TrafficInformations on g.Key.Id equals tr.Id
               select new BasicInfo
               {

                  TrafficInformationId = tr.Id,
                  Lat = tr.Location.Coord.Latitude,
                  Long = tr.Location.Coord.Longitude,
                  LocationText = tr.Location.Name,
                  EventClassId = tr.TMC.EventInfoes.Where(e => e.EventOrder == 1).FirstOrDefault().FK_UpdateClassId
               };

Zkusil jsem i, to vše dát do group by, je tam problém s typem DbGeograhpy, ale takhle to funguje:

  var query = from t in db.TrafficInformations
              where t.ValidFrom < now && t.ValidTo > now && t.Type == type
              group t by new { t.FK_JsdiId, t.Version,t.Id,t.Location.Name,t.Location.Coord.Latitude,t.Location.Coord.Longitude,t.TMC } into g
              select new BasicInfo
              {

               TrafficInformationId = g.Key.Id,
               Lat = g.Key.Latitude,
               Long = g.Key.Longitude,
               LocationText = g.Key.Name,
               EventClassId = g.Key.TMC.EventInfoes.Where(e => e.EventOrder == 1).FirstOrDefault().FK_UpdateClassId
               };

Varianta s joinem zdá se být malinko rychlejší.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Tak konečně jsem přišel na funkční a snad i spravné řešení:

   var query = from t in db.TrafficInformations
               group t.Version by t.FK_JsdiId into g
               join tr in db.TrafficInformations
               on new { ID = g.Key, Version = g.Max() } equals new { ID = tr.FK_JsdiId, Version = tr.Version }
               where tr.ValidFrom < now && tr.ValidTo > now && tr.Type == type
               select new BasicInfo
                 {
                    TrafficInformationId = tr.Id,
                    Lat = tr.Location.Coord.Latitude,
                    Long = tr.Location.Coord.Longitude,
                    LocationText = tr.Location.Name,
                    EventClassId = tr.TMC.EventInfoes.Where(e => e.EventOrder == 1).FirstOrDefault().FK_UpdateClassId
                 };

Sice ve vygenerovaném dotazu je jeden join zbytečný (když jsem ho smazal, tak výsledek byl pořád stejný), ale to asi dělá EF automaticky v případě vazby 1:1 do jiné tabulky.

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback