2016-08-14 27 views
5

Próbuję przekonwertować to zapytanie, używając składni zapytania linq do składni opartej na metodzie.Jak zrobić lewe sprzężenie zewnętrzne w Entity Framework bez użycia składni zapytania?

Oto zapytanie:

var products = from p in context.Products 
       join t in context.TopSellings 
       on p.Id equals t.Id into g 
       from tps in g.DefaultIfEmpty() 
       orderby tps.Rating descending 
       select new 
       { 
        Name = p.Name, 
        Rating = tps.Rating == null ? 0 : tps.Rating 
       }; 

zapytanie powyżej produkuje tego zapytania sql:

{SELECT 
    [Project1].[Id] AS [Id], 
    [Project1].[Name] AS [Name], 
    [Project1].[C1] AS [C1] 
    FROM (SELECT 
     [Extent1].[Id] AS [Id], 
     [Extent1].[Name] AS [Name], 
     CASE WHEN ([Extent2].[Rating] IS NULL) THEN 0 ELSE [Extent2].[Rating] END AS [C1], 
     [Extent2].[Rating] AS [Rating] 
     FROM [dbo].[Products] AS [Extent1] 
     LEFT OUTER JOIN [dbo].[TopSellings] AS [Extent2] ON [Extent1].[Id] = [Extent2].[Id] 
    ) AS [Project1] 
    ORDER BY [Project1].[Rating] DESC} 

tej pory co Próbowałem jest mniej więcej tak:

var products = context.Products 
    .Join(inner: context.TopSellings.DefaultIfEmpty(), 
      outerKeySelector: c => c.Id, innerKeySelector: y => y.Id, 
      resultSelector: (j, k) => new { Name = j.Name, Rating = k.Rating == null ? 0 : k.Rating }) 
    .OrderByDescending(p => p.Rating); 

i ten tworzy inną kwerendę sql (co oczywiście ma inne znaczenie w odniesieniu do tego, w jaki sposób dane są bei ng użyte w programie):

{SELECT 
    [Project1].[Id] AS [Id], 
    [Project1].[Name] AS [Name], 
    [Project1].[C1] AS [C1] 
    FROM (SELECT 
     [Extent1].[Id] AS [Id], 
     [Extent1].[Name] AS [Name], 
     CASE WHEN ([Join1].[Rating] IS NULL) THEN 0 ELSE [Join1].[Rating] END AS [C1] 
     FROM [dbo].[Products] AS [Extent1] 
     INNER JOIN (SELECT [Extent2].[Id] AS [Id], [Extent2].[Rating] AS [Rating] 
      FROM (SELECT 1 AS X) AS [SingleRowTable1] 
      LEFT OUTER JOIN [dbo].[TopSellings] AS [Extent2] ON 1 = 1) AS [Join1] ON [Extent1].[Id] = [Join1].[Id] 
    ) AS [Project1] 
    ORDER BY [Project1].[C1] DESC} 

Twoje odpowiedzi będą bardzo pomocne i będą bardzo mile widziane!

+0

Takie konwersje nie ma sensu do mnie, ale tak czy owak, odpowiednik składnia metodą użyłby 'GroupJoin' następnie' SelectMany', nadzieję, że można to zrobić samemu stamtąd. –

+0

Zobacz msdn: https://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b – jdweng

+0

@IvanStoev wyłącznie do celów edukacyjnych. –

Odpowiedz

5

Generalnie można uzyskać dokładne wyrażenie używane w dowolnym wyrażeniu zapytania, uzyskując dostęp do właściwości zapytania z zakresu Expression. Następnie przeanalizuj to wyrażenie i odtwórz je.

var expr = products.Expression; 

Z drugiej strony każde wyrażenie używające składni zapytania ma proste tłumaczenie do przodu. Połączenie z częścią into odpowiada klauzuli GroupJoin(), podczas gdy dodatkowe klauzule from odpowiadają SelectMany(). To powinno produkować równoważne zapytania:

var products = context.Products.GroupJoin(context.TopSellings, 
     p => p.Id, t => t.Id, (p, g) => new { p, g }) 
    .SelectMany(x => x.g.DefaultIfEmpty(), 
     (x, tps) => new { x.p, x.g, tps }) 
    .OrderByDescending(x => x.tps.Rating) 
    .Select(x => new { x.p.Name, Rating = x.tps.Rating == null ? 0 : x.tps.Rating }); 

Ale można usunąć niektórych zwolnień cięcia zmiennych, które nie są używane i skorzystać z kilku przydatnych operatorów. Należy pamiętać, że może to wpłynąć na faktyczne zapytanie, więc nie jest dokładnie dopasowane, ale powinno być wystarczająco blisko.

var products = context.Products.GroupJoin(context.TopSellings, 
    p => p.Id, t => t.Id, 
    (p, g) => g.DefaultIfEmpty() 
     .OrderByDescending(tps => tps.Rating) 
     .Select(tps => new { p.Name, Rating = tps.Rating ?? 0 }) 
); 
+0

wow, to jest dokładnie to! dzięki człowieku, btw, dobra wskazówka na temat tej "ekspresji" nieruchomości, o której wspomniałeś, chociaż jest to trochę "tajemnicze", aby przeczytać ... jeśli przeanalizujesz to dokładnie ... to ma sens! Dzięki. –

-2
using EF 

AAWSADBEntitiesContext = new AAWSA_DBEntitiesContext(); 
     // .Where(pp1 => ((zemechaObj.DriverId == pp1.DriverId) || (zemechaObj.DriverId == pp1.DriverId))) 
     var myresult =(from zemechaObj in AAWSADBEntitiesContext.WaterSupplyForwardedZemechResourses 
         where zemechaObj.CompanyId == companyId && zemechaObj.Status == WaterSupplyServiceRequest.Shared.ToString() 

         from driverObj in AAWSADBEntitiesContext.tbl_Driver 
           .Where(driver => ((zemechaObj.DriverId == driver.DriverId))) 
           .DefaultIfEmpty() 
          //fromBranch 
         from fromBranch in AAWSADBEntitiesContext.tbl_CompanyRegistrationInformation 
           .Where(fromB => ((zemechaObj.FromBranchId == fromB.CompanyId))) 

          //toBranch 
         from toBranch in AAWSADBEntitiesContext.tbl_CompanyRegistrationInformation 
           .Where(toB => ((zemechaObj.ToBranchId == toB.CompanyId))) 
           //vehicle 
          from vehicleObj in AAWSADBEntitiesContext.tbl_Vehicle 
           .Where(veh => ((zemechaObj.VehicleId == veh.VehicleId))) 
            .DefaultIfEmpty() 
           //assistant one 
         from DriverAssistantOneObj in AAWSADBEntitiesContext.tbl_DriverAssistant 
           .Where(driverAssistOne => ((zemechaObj.DriverAssitantFirstID == driverAssistOne.DriverAssistantId))) 
           .DefaultIfEmpty() 
          //assistant one 
         from DriverAssistantTwoObj in AAWSADBEntitiesContext.tbl_DriverAssistant 
           .Where(driverAssistTwo=> ((zemechaObj.DriverAssitantSecondID == driverAssistTwo.DriverAssistantId))) 
           .DefaultIfEmpty() 
          select new BranchResourceForZemechaEntities() 
          { 
           ForwaredResourseID = zemechaObj.ForwaredResourseID, 
           ServiceStartDate = zemechaObj.ServiceStartDate.ToString(), 
           ServiceEndDate = zemechaObj.ServiceEndDate.ToString(), 
           ForwaredDate = zemechaObj.ForwaredDate.ToString(), 
           Status = zemechaObj.Status, 
           Comment = zemechaObj.Comment, 
           //from Branch 
           FromBranchName = fromBranch.CompanyName, 
           //To Branch 
           ToBranchName = toBranch.CompanyName, 
           VehicleId = zemechaObj.VehicleId, 
           //Vehicle info 
           PlateNumber = vehicleObj.PlateNumber+" ", 
           DriverId = zemechaObj.DriverId, 
           //Driver Full Name 
           DriverFullName = driverObj.FirstName + " " + driverObj.MiddleName + " " + driverObj.LastName, 
           // Driver Assitant one Full Name 
           DriverAssitantFirstID = zemechaObj.DriverAssitantFirstID, 
           DriverAssistantOneFullName = DriverAssistantOneObj.FirstName + " " + DriverAssistantOneObj.MiddleName + " " + DriverAssistantOneObj.LastName, 
           // Driver Assitant Two Full Name 
           DriverAssitantSecondID = zemechaObj.DriverAssitantSecondID, 
           DriverAssistantTwoFullName = DriverAssistantTwoObj.FirstName + " " + DriverAssistantTwoObj.MiddleName + " " + DriverAssistantTwoObj.LastName, 

           CompanyId = zemechaObj.CompanyId, 
           FromBranchId = zemechaObj.FromBranchId, 
           ToBranchId = zemechaObj.ToBranchId, 
           BrLoggedUserId = zemechaObj.BrLoggedUserId.ToString() 

          }).ToList(); 
     return myresult.ToList<BranchResourceForZemechaEntities>(); 
+0

Proszę nie po prostu zrzucić blok kodu - zamiast tego objaśnij swoje rozwiązanie. – Moritz