EntityModel est défini comme suit: Personnel a un lien vers un pays
Lors de l'exécution de ce code dans LinqPad, je constate que le code SQL généré n'est pas optimisé (tous les champs sont renvoyés) dans la première requête? Qu'est-ce qui me manque ici ou ce qui ne va pas?
Requête 1 LINQ
var Country = Countries.FirstOrDefault(o => o.Id == 100000581);
var personnelIds = Country.Personnels.Select(p => p.Id).ToArray();
personnelIds.Dump();
Requête 1 SQL
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
Requête 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();
Requête 2 SQL
exec sp_executesql N'SELECT [t0].[Id] FROM [Personnel] AS [t0] WHERE [t0].[Country_Id] = @p0',N'@p0 bigint',@p0=100000581
La base de données utilisée est SQL Express 2008. La version de LinqPad est la version 4.43.06.
//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();
Essayez ceci, ça devrait être mieux.
La collection Personnels sera remplie via un chargement différé lors de l'accès, ce qui permettra d'extraire tous les champs de la base de données. Voici ce qui se passe ...
// 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();
Vous voulez quelque chose de plus comme ça:
// 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();
OU:
var result = personnelIdsQuery.SingleOrDefault();
Ensuite, obtenez le tableau d'ID sinon NULL
if( null != result )
{
var personnelIds = result.PersonnelIds;
}
Essayez peut également essayer de regrouper le personnel dans une seule requête
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);
La ForeignKey est-elle explicitement définie dans votre POCO for Personnel? Il est courant de le laisser dans EF, mais son ajout simplifierait considérablement ce code et le code SQL résultant:
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();