使用linq选择特定列:什么被转移?

时间:2013-01-15 12:42:58

标签: sql linq orm

我参考这个例子:Return selected specified columns

引用: 如果BlobDetails不是LINQ实体,那么您可以直接执行:

var qry = from b in dc.Blobs
          orderby b.RowVersion descending
          select new BlobDetails {
              Id = b.Id, Size = b.Size,
              Signature = b.Signature, RowVersion = b.RowVersion};

return qry.ToList();

我看到他们正在通过ORM工具LINQ TO SQL在查询中选择特定列。 ORM工具的批评者说,如果我没记错的话,ORM工具会从表中选择并返回整个对象,并限制只选择特定列的选项,就像通过经典的SQL编程一样。当然,当我看到这个例子时,我对此表示怀疑,但是,我仍然不断问自己这样一个问题:数据库是仅返回所选列,还是返回整个对象,将列过滤留给ORM工具?

从这个例子中,他们还有一个名为Blobdetails的类:

public class BlobDetails   
{  
    public int Id { get; set; }  
    public string Signature { get; set; }  
    public int Size { get; set; }  
    public System.Data.Linq.Binary RowVersion { get; set; }     
}

每次我只想通过LINQ从表中选择几列时,是否需要创建自己的类?

4 个答案:

答案 0 :(得分:13)

您不需要创建新类来从表中选择几列。您可以使用匿名类型。

var qry = from b in dc.Blobs
          orderby b.RowVersion descending
          select new { b.Id, b.Size, b.Signature, b.RowVersion};

return qry.ToList();

仅传输选定的列。使用纯SQL和使用LINQ to SQL没有区别。在执行LINQ查询时,它将转换为纯SQL并执行。然后将结果映射到您的对象。

您可以使用SQL Server Profiler查看在服务器上生成和执行的查询。您还可以使用LINQPad查看从查询中生成的SQL。在您的情况下,查询将使用BlobDetails或匿名对象:

SELECT [t0].[Id], [t0].[Size], [t0].[Signature], [t0].[RowVersion]
FROM [Blobs] AS [t0]
ORDER BY [t0].[RowVersion] DESC

答案 1 :(得分:2)

我认为您第一个问题的答案已经在您提到的POST中。然而...

如果BlobDetails不是LINQ实体,您可以在select语句中使用它来定义(缩小)投影属性。例如:

var qry = from b in dc.Blobs
          select new BlobDetails { Id = b.Id, Size = b.Size }

将编译为SQL查询,如SELECT Id, Size FROM Blob ....

但如果BlobDetails是LINQ实体,则需要使用AsEnumerable()黑客,否则您将获得NotSupportedException: Explicit construction of entity type in query is not allowed

var qry = from b in dc.Blobs.AsEnumerable()
          select new BlobDetails { Id = b.Id, Size = b.Size }

修改

正如@Chris Pitman在评论中指出的那样,这种AsEnumerable()方法可能会造成严重的瓶颈,因为在应用投影之前整个表格会被加载到内存中。 所以不推荐!

关于你的第二个问题:

您需要为在方法范围之外轻松使用的对象创建自定义类。匿名对象的属性仅在作用域中可见,它们已声明,并且匿名对象只能转换为类型object

因此,如果您想从方法中返回匿名对象,则返回类型必须是@ objectdynamic的可枚举,如@xeondev在其评论中所述。

答案 2 :(得分:2)

当您进行投影时,LINQ确实只选择了那些列,并且没有任何东西可以阻止您根据需要实现它。所以在你的示例代码中

select new BlobDetails 
{
  Id = b.Id, 
  Size = b.Size,
  Signature = b.Signature, 
  RowVersion = b.RowVersion
};

只有b.id,b.size,b.signature,& b.rowversion被选中。你可以使用sql profiler或你的调试器验证这一点,我似乎记得你还可以在datacontext上调用一个函数来获取最后运行的查询。

答案 3 :(得分:1)

无需创建自己的类,您可以返回匿名类型。你可以写这样的东西

var qry = from b in dc.Blobs
          orderby b.RowVersion descending
          select new {
              Id = b.Id, Size = b.Size,
              Signature = b.Signature, RowVersion = b.RowVersion};

return qry.ToList();

虽然该方法的签名应该看起来像这样

public  IEnumerable<object> GetItems()

public dynamic GetItems()

因此,如果您要在外部作用域中使用linq查询的结果(如示例所示),强烈建议您创建自己的类。