29

EntityModel は次のように定義されています: 人員は国へのリンクを持っています

LinqPad でこのコードを実行すると、最初のクエリで生成された SQL が最適化されていない (すべてのフィールドが返される) ことがわかります。ここで何が欠けているか、間違っていますか?

クエリ 1 LINQ

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

クエリ 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



クエリ 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();

クエリ 2 SQL

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


使用するデータベースは SQL Express 2008 です。LinqPad のバージョンは 4.43.06 です。

4

4 に答える 4

44
//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();

これを試してください、それはより良いはずです。

于 2013-03-28T19:47:25.290 に答える
4

Personnels コレクションは、アクセス時に遅延読み込みによって入力されるため、DB からすべてのフィールドを取得します。ここで何が起こっている...

// 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();

あなたはこのようなものがもっと欲しい:

// 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();

また:

var result = personnelIdsQuery.SingleOrDefault();

次に、null でない場合は ID の配列を取得します

if( null != result )
{
    var personnelIds = result.PersonnelIds;
}
于 2013-03-29T00:10:48.437 に答える
1

Try は、人員を 1 つのクエリにグループ化することもできます

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);
于 2013-03-28T20:26:03.727 に答える
0

人事の POCO で明示的に定義された ForeignKey がありますか? EF では省略するのが一般的ですが、追加すると、このコードと結果の 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();
于 2013-03-28T23:44:02.657 に答える