我引用这个例子:返回选定的指定列
引用:如果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从表中选择几列吗?
您不需要创建新的类来从表中选择一些列。您可以使用匿名类型。
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
当您做投影时,LINQ确实只选择那些列,并且没有任何东西可以阻止您实现它。在你的示例代码
中select new BlobDetails
{
Id = b.Id,
Size = b.Size,
Signature = b.Signature,
RowVersion = b.RowVersion
};
只有b.id, b.size, b.signature, &b.选择行版本。你可以用sql分析器或调试器来验证这一点,我似乎记得还有一个函数,你可以在数据上下文中调用,以获得运行的最后一个查询。
我认为你第一个问题的答案已经在你提到的POST中了。然而…
如果你的BlobDetails
不是LINQ实体,你可以简单地在你的select
语句中使用它来定义(收缩)你的投影属性。例如:
var qry = from b in dc.Blobs
select new BlobDetails { Id = b.Id, Size = b.Size }
将编译成类似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()
方法可能会造成严重的瓶颈,因为在应用投影之前,整个表将被加载到内存中。所以不推荐!
对于你的第二个问题:
您需要为您希望在方法作用域之外轻松使用的对象创建自定义类。匿名对象的属性只在作用域中可见,并且匿名对象只能被强制转换为object
类型。
所以如果你想从方法中返回匿名对象,返回类型必须是object
或dynamic
的可枚举值,正如@xeondev在他的评论中所说的。
不需要创建自己的类,可以返回匿名类型。你可以这样写
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查询的结果,就像你的例子建议的那样,强烈建议你创建自己的类。