2015-10-13 12 views
8

Chcę załadować dane przez numer wiersza na partycję za pomocą EF.Row_number over (Partition by yyy) w Entity Framework

SELECT * 
    FROM (
     SELECT sf.SerialFlowsId 
        ,sf.GoodsSerialId 
        ,d.FormTypeId 
        , d.GoodsId 
        ,ROW_NUMBER() OVER (PARTITION BY d.GoodsId, sf.GoodsSerialId ORDER BY sf.Date DESC)row 
     FROM sam.SerialFlows sf 
     INNER JOIN sam.Detail d ON d.DetailId = sf.DetailId 
     )z 
WHERE z.row =1 
     AND z.FormTypeId=7 
     AND z.GoodsId=51532 

to zapytanie jest moim oczekiwaniem.

próbuję użyć tego wyrażenia, ale niestety Zip metoda rozszerzenie nie rozpoznać w ef

var goodsSerials = context.SerialFlows.OrderByDescending(x => x.Date).GroupBy(x => new { x.Detail.GoodsID, x.Date }) 
        .Select(g => new {g}) 
        .SelectMany(z => z.g.Select(c => c)).Zip(m, (j, i) => new { GoodSerial=j,j.Detail.FormTypeID,j.Detail.GoodsID,rn=i }) 
        .Where(x => x.rn== 1 && x.GoodsID== goodsId && x.FormTypeID==7).Select(x => x.GoodSerial).ToList(); 

mam więcej niż 20000000 rekordy w tabeli SerialFlows.

** Zmieniano

var goodsSerials = context.SerialFlows 
              .Where(e => e.Detail.GoodsID == goodsId) 
              .GroupBy(x => x.GoodsSerialID) 
              .Select(g => g.OrderByDescending(e=>e.Date).Take(1)) 
              .SelectMany(e => e.Where(x=>x.Detail.FormTypeID==7).Select(z=>z.GoodsSerial)).ToList(); 

*** rozwiązywane przez tego zapytania

 var goodsSerials = context.SerialFlows 
              .Include(x => x.Detail) 
              .Where(e => e.Detail.GoodsID == goodsId) 
              .GroupBy(x => x.GoodsSerialID) 
              .Select(g => g.OrderByDescending(e => e.Date).Take(1).Where(x=>x.Detail.FormTypeID==7)) 
              .SelectMany(e => e.Select(z => z.GoodsSerial)).ToList(); 
+2

Dlaczego spadamy? Wydaje mi się to bardzo dobrym pytaniem. – pseudocoder

Odpowiedz

8

Od zapytaniu SQL, myślę, że trzeba do pierwszej grupy, co je wszystkie w PARTITION BY klauzuli zamówić każdy Grupuj według daty. Następnie projektuj każdą grupę, aby zawierała każdy wpis z indeksem. Następnie SelectMany, aby spłaszczyć wszystkie grupy, a następnie zastosować filtr i ostatecznie wyświetlić żądany wynik. Widać, że w ogóle nie potrzebujemy tak zwanego Zip.

Edit: bo trzeba filtrować liczbę wierszy, ale wygląda na to sposobu Select przyjmującą Expression<Func<T,int,TResult>> nie jest obsługiwana (a także sposobu w LINQ Zip Do podmiot). Nie sądzę, że jest to problem z budowaniem drzewa Expression, co oznacza, że ​​nawet budowanie go ręcznie, nadal nie będzie obsługiwane. Myślę, że możesz użyć trochę pracy, w której możesz nadal filtrować żądany wiersz, używając zamiast tego Skip i Take.

Następujący kod filtruje tylko pierwszy wiersz w każdym z grupy (równoważnym do stanu rn == 1):

var goodsSerials = context.SerialFlows 
          .Where(e => e.Detail.GoodsID == goodsId && 
             e.Detail.FormTypeID == 7) 
          .GroupBy(x => new { x.Detail.GoodsID, x.GoodsSerialId }) 
          .Select(g => g.OrderByDescending(e => e.Date) 
             .Take(1)) 
          .SelectMany(e => e).ToList(); 

The Where filtry tylko 1 wartości GoodsID więc GroupBy nie musi zawierać GoodsID na klucz, tak byłoby prościej tak:

var goodsSerials = context.SerialFlows 
          .Where(e => e.Detail.GoodsID == goodsId && 
             e.Detail.FormTypeID == 7) 
          .GroupBy(x => x.GoodsSerialId) 
          .Select(g => g.OrderByDescending(e => e.Date).Take(1)) 
          .SelectMany(e => e).ToList(); 

mam nadzieję, że rozumiesz ideę korzystania Skip i Take do zastosowania w różnych przypadkach.

+0

niezawodnie mam błąd. Dodatkowe informacje: LINQ do Entities nie rozpoznaje metody "System.Collections.Generic.IEnumerable –

+0

@MahdiFarhani zobacz moją edycję, wygląda na to, że prawie nie możemy wyodrębnić numeru wiersza, ale do celów filtrowania mamy całkiem dobrą pracę. –

+0

jest uruchamiany, ale wydajność nie jest akceptowalna. Zajmie to 4 minuty i anulowałem to. –