【问题标题】:Select only a single column in LINQ在 LINQ 中只选择一列
【发布时间】:2013-03-28 19:43:40
【问题描述】:

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

【问题讨论】:

    标签: linq entity-framework select


    【解决方案1】:
    //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();
    

    试试这个,应该会更好。

    【讨论】:

    • 我实际上想通过 Country 对象检索 Personnels,如查询 1 中所述。我不明白的是所有列都被获取,而不仅仅是 Id 列
    【解决方案2】:

    人员集合将在访问时通过延迟加载填充,因此从数据库中检索所有字段。这就是正在发生的事情......

    // 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;
    }
    

    【讨论】:

      【解决方案3】:

      尝试也可以尝试将人员分组到单个查询中

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

      【讨论】:

        【解决方案4】:

        您的 POCO 中是否明确定义了 ForeignKey for Personnel?在 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();
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-08-07
          • 2021-12-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多