2013-03-28 17 views
17

EntityModel jest zdefiniowany jako: Kadr ma link do krajuWybierz tylko jedną kolumnę w LINQ

Podczas wykonywania tego kodu w LINQPad, widzę, że SQL, który jest generowany nie jest zoptymalizowany (wszystko pola są zwracane) w pierwszym zapytaniu? Czego tu brakuje lub robię źle?

Zapytanie 1 LINQ

var Country = Countries.FirstOrDefault(o => o.Id == 100000581); 
var personnelIds = Country.Personnels.Select(p => p.Id).ToArray(); 
personnelIds.Dump(); 

zapytań SQL 1

exec sp_executesql N'SELECT [t0].[Id], [t0].[Version], [t0].[Identifier], [t0].[Name], , [t0].[UpdatedBy] FROM [Personnel] AS [t0] WHERE [t0].[Country_Id] = @p0',N'@p0 bigint',@p0=100000581 



Zapytanie 2 LINQ

var Country = Countries.FirstOrDefault(o => o.Id == 100000581); 
var personnelIds2 = Personnels.Where(p => p.Country == Country).Select(p => p.Id).ToArray(); 
personnelIds2.Dump(); 

Query 2 SQL

exec sp_executesql N'SELECT [t0].[Id] FROM [Personnel] AS [t0] WHERE [t0].[Country_Id] = @p0',N'@p0 bigint',@p0=100000581 


Baza używany jest SQL Express 2008. A wersja LINQPad jest 4.43.06

Odpowiedz

24
//var Country = Countries.FirstOrDefault(o => o.Id == 100000581); 
var personnelIds = context.Personnels 
    .Where(p => p.Country.Id == 100000581) 
    .Select(p => p.Id) 
    .ToArray(); 

personnelIds.Dump(); 

Spróbuj, powinno być lepiej .

+0

Naprawdę chcę pobrać Personnels za pośrednictwem obiektu Country jako de wypisane w Zapytaniu 1. Nie rozumiem, że wszystkie kolumny są pobierane, a nie tylko kolumna Id –

1

Spróbuj można także spróbować zgrupowanie kadry w jednym zapytaniu

var groups = 
    (from p in Personnel 
    group p by p.CountryId into g 
    select new 
    { 
     CountryId = g.Key 
     PersonnelIds = p.Select(x => x.Id) 
    }); 
var personnelIds = groups.FirstOrDefault(g => g.Key == 100000581); 
0

Czy masz ForeignKey wyraźnie zdefiniowany w POCO dla personelu? To wspólne zostawić go w EF, ale dodanie go byłoby znacznie uprości zarówno ten kod i wynikowy SQL:

public class Personnel 
{ 
    public Country Country { get; set; } 

    [ForeignKey("Country")] 
    public int CountryId { get; set; } 

    . . . 
} 

> update-database -f -verbose 

var ids = db.Personnel.Where(p => p.CountryId == 100000581).Select(p => p.Id).ToArray(); 
2

personnels kolekcja zostanie wypełniona przez leniwe załadunku, gdy dostępne, dlatego zdobycie wszystkich pól z DB . Oto, co się dzieje ...

// retrieves data and builds the single Country entity (if not null result) 
var Country = Countries.FirstOrDefault(o => o.Id == 100000581); 

// Country.Personnels accessor will lazy load and construct all Personnel entity objects related to this country entity object 
// hence loading all of the fields 
var personnelIds = Country.Personnels.Select(p => p.Id).ToArray(); 

Chcesz coś więcej tak:

// build base query projecting desired data 
var personnelIdsQuery = dbContext.Countries 
    .Where(c => c.Id == 100000581) 
    .Select(c => new 
     { 
      CountryId = c.Id, 
      PersonnelIds = c.Personnels.Select(p => p.Id) 
     } 

// now do enumeration 
// your example shows FirstOrDefault without OrderBy 
// either use SingleOrDefault or specify an OrderBy prior to using FirstOrDefaul 

var result = personnelIdsQuery.OrderBy(item => item.CountryId).FirstOrDefault(); 

czyli

var result = personnelIdsQuery.SingleOrDefault(); 

następnie uzyskać tablicę identyfikatorów jeśli nie zerowy

if(null != result) 
{ 
    var personnelIds = result.PersonnelIds; 
} 
Powiązane problemy