我参考这个例子: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从表中选择几列时,是否需要创建自己的类?
答案 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
。
因此,如果您想从方法中返回匿名对象,则返回类型必须是@ object
或dynamic
的可枚举,如@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查询的结果(如示例所示),强烈建议您创建自己的类。