10

我参考这个例子:返回选定的指定列

Quote: 如果 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

4 回答 4

14

您无需创建新类即可从表中选择几列。您可以为此使用匿名类型。

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
于 2013-01-15T14:07:42.103 回答
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()hack,否则您将获得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()方法可能会造成严重的瓶颈,因为在应用投影之前整个表将加载到内存中。所以不推荐!

对于你的第二个问题:

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

因此,如果您想从方法返回匿名对象,则返回类型必须是可枚举的,object或者dynamic正如@xeondev 在他的评论中所说的那样。

于 2013-01-15T13:52:58.147 回答
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 来获取运行的最后一个查询。

于 2013-01-15T13:54:08.507 回答
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 查询的结果,强烈建议您创建自己的类。

于 2013-01-15T12:53:48.910 回答