Linq-to-entities generic == soluție

Am o interogare LINQ către entități

IQueryable> GetFirstOperationsForEveryId
    (IQueryable> ItemHistory)
{
    var q = (from h in ItemHistory
             where h.OperationId ==
                (from h1 in ItemHistory
                 where h1.GenericId == h.GenericId
                 select h1.OperationId).Min()
             select h);
    return q;
}

ItemHistory is a generic query. It can be obtained in the following way

var history1 = MyEntitiySet1.Select(obj =>
    new History{ obj.OperationId, GenericId = obj.LongId });
var history2 = AnotherEntitiySet.Select(obj =>
    new History{ obj.OperationId, GenericId = obj.StringId });

In the end of all I want a generic query being able to work with any entity collection convertible to History.

Problema este că codul nu compilează din cauza comparației GenericId din interogarea internă (operatorul '==' nu poate fi aplicat operanzilor de tip 'T' și 'T').

Dacă schimbați == la h1.GenericId.Equals (h.GenericId) primesc următoarea NotSupportedException :

Nu se poate afișa tipul "System.Int64" pentru a tasta "System.Object". LINQ către entități acceptă numai tipuri primitive de tip Entity Data Model.

Am încercat să fac gruparea în loc de subchetare și să mă alătur rezultatelor.

IQueryable> GetFirstOperationsForEveryId
    (IQueryable> ItemHistory)
{
    var grouped = (from h1 in ItemHistory
                   group h1 by h1.GenericId into tt
                   select new
                   {
                        GenericId = tt.Key,
                        OperationId = tt.Min(ttt => ttt.OperationId)
                   });

    var q = (from h in ItemHistory
             join g in grouped
                on new { h.OperationId, h.GenericId }
                equals new { g.OperationId, g.GenericId }
             select h);
    return q;
}

Se compilează deoarece GenericId-urile sunt comparate cu cuvântul cheie equals și funcționează, dar interogarea cu date reale este prea lentă (a funcționat timp de 11 ore pe serverul postgresql dedicat).

Există o opțiune de a construi o expresie întregă pentru afirmația exterioară. Dar codul ar fi prea lung și neclar.

Există soluții simple pentru compararea egalității cu generice în LINQ către entități?

2

4 răspunsuri

Încearcă asta, cred că ar trebui să realizeze ceea ce vrei fără interogarea/aderarea suplimentară

IQueryable> GetFirstOperationsForEveryId
    (IQueryable> ItemHistory)
{
  var q = from h in ItemHistory
          group h by h.GenericId into tt
          let first = (from t in tt
                        orderby t.GenericId
                        select t).FirstOrDefault()
          select first;

  return q;
}
1
adăugat
Destul de elegantă soluție! Dar, din nefericire, nu este implementat încă în Npgsql (din data de 2.0.11.92). System.Data.EntityCommandCompilationException: A apărut o eroare la pregătirea definiției comenzii. ---> System.NotImplementedException: Metoda sau operațiunea nu este implementată. Problema mea reală a fost că am uitat să creez indexuri. De aceea interogarea grup + join a lucrat 11 ore. Cu indicii rulează destul de repede.
adăugat autor Mike, sursa

De asemenea, ați putea stabili o constrângere generică pe T pentru o inteface IItemHistory care implementează proprietatea GenericId și OperationId.

0
adăugat

Întrebarea mea conține deja o soluție. Cea de-a doua metodă cu grup + join funcționează bine dacă tabela este indexată corespunzător . Este nevoie de 3,28 secunde pentru a prelua rânduri de 370k din tabela de baze de date. De fapt, în varianta non-generică, prima interogare este mai lentă pe postgresql decât cea de-a doua. 26,68 secunde vs 4,75.

0
adăugat
IQueryable> GetFirstOperationsForEveryId
(IQueryable> ItemHistory)
{
var grouped = (from h1 in ItemHistory
               group t by h1.GenericId into tt
               select new
               {
                    GenericId = tt.Key,
                    OperationId = tt.Min(ttt => ttt.OperationId)
               });

var q = (from h in ItemHistory
         join g in grouped
            on new { h.OperationId, h.GenericId }
            equals new { g.OperationId, g.GenericId }
         select h);
return q;
}
0
adăugat
Care este diferența față de ceea ce am postat?
adăugat autor Mike, sursa