10

I refer to this example: Return selected specified columns

Quote: If BlobDetails isn't the LINQ entity, then you can do it directly:

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

I see that they are selecting specific column in a query through the ORM-tool LINQ TO SQL. Critics of ORM-tools say that, if I remember correctly, that ORM-tools select and return entire objects from the table, and limits the options of selecting only specific columns as one can do through classic SQL-programming. Of course, I have my doubts about that when I see this example, but nevertheless, I still keep asking myself the question: Does the database return only the selected columns, or does it return the entire objects, leaving the column-filtering to the ORM-tool?

From this example, they also have a class called 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; }     
}

Do I need to create my own classes everytime I only wish to select a few columns from a table through LINQ?

Community
  • 1
  • 1
Darth_Sygnious
  • 528
  • 3
  • 7
  • 18
  • 2
    Just step with the debugger after qry object is created and you can see what SQL query is actually generated ;-) or try LINQpad. – mipe34 Jan 15 '13 at 12:57

4 Answers4

14

You don't need to create new classes to select few columns from a table. You can use anonymous types for that.

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

return qry.ToList();

Only selected columns are transferred. There is no difference between using plain SQL and using LINQ to SQL. When you are executing LINQ query, it is converted to plain SQL and executed. Then result is mapped to your objects.

You can use SQL Server Profiler to see what query was generated and executed on server. Also you can use LINQPad to see what SQL will be generated from your query. In your case query will be same either you use BlobDetails or anonymous object:

SELECT [t0].[Id], [t0].[Size], [t0].[Signature], [t0].[RowVersion]
FROM [Blobs] AS [t0]
ORDER BY [t0].[RowVersion] DESC
Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
  • There's also the very handy `DataContext#Log` property, which can be set to any `TextWriter` (such as [this one](http://stackoverflow.com/a/4234085/157247)) and shows you what Linq-to-sql is up to. – T.J. Crowder Jun 22 '15 at 13:58
2

I think that the answer to your first question is already in the POST you mentioned. However...

If your BlobDetails is not LINQ entity you can simply use it in your select statement to define (shrink) your projection attributes. For example:

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

would compile to SQL query like SELECT Id, Size FROM Blob ....

But if BlobDetails is LINQ entity you will need to use that AsEnumerable() hack otherwise you will get 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 }

Edit

As @Chris Pitman stated in his comment this AsEnumerable() approach could create serious bottleneck, beacause the whole table would be loaded in memory before applying the projection. So it is not recommended!

To your second question:

You will need to create custom class for objects that you want use easily outside the scope of the method. Properties of an anonymous object are visible only in the scope, where they have been declared and anonymous objects can be cast only to type object.

So if you want to return anonymous objects from method the return type would has to be an enumerable of object or dynamic as @xeondev stated in his comment.

mipe34
  • 5,596
  • 3
  • 26
  • 38
  • 1
    I would suggest never doing the second form, since it *will* pull back entire records even if not needed. Additionally, it would be too easy for someone who does not understand to pull back an entire table. – Chris Pitman Jan 15 '13 at 14:19
2

when you do projections LINQ does indeed only select those columns and there is nothing preventing you from materializing it however you want. So in your example code

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

Only b.id, b.size, b.signature, & b.rowversion are selected. You can verify this with sql profiler or your debugger, I seem to recall there is also a function you can call on the datacontext to get the last query that was ran.

iamkrillin
  • 6,798
  • 1
  • 24
  • 51
  • This is the most direct answer to the real question. Being able to restrict queries to a subset of fields is one of the features that makes L2S and EF stand out compared to other ORMs. It makes writing performant query routines much much easier! – Chris Pitman Jan 15 '13 at 14:24
  • (Shameless plug) Check out saucedb (http://sauce.codeplex.com) If you like L2S and EF you might really like the feature set offered by it. It allows for LINQ style queries while adding some other neat features. Disclaimer: I wrote it – iamkrillin Jan 15 '13 at 17:06
1

There's no need to create your own classes, you can return an anonymous type. You can write something like this

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

Although the signature of the method should look to something like this

public  IEnumerable<object> GetItems()

or

public dynamic GetItems()

So if you are going to use the result of linq query in outer scope like you example suggest, it is highly recommended you create your own classes.

Esteban Elverdin
  • 3,552
  • 1
  • 17
  • 21
  • The return type is an Anonymous Type, check this link that will explain you in detail what an anonymous type is: http://msdn.microsoft.com/en-us/library/bb397696.aspx – Esteban Elverdin Jan 15 '13 at 13:06
  • I know what is an Anonymous type. In your example the return type will have to be some Enumerable of objects. I just wanted to point out that it is not very usable to return enumerable of objects you do not know anything about. So to OP's question: you should use own class if you want to use that objects in some outer scope. – mipe34 Jan 15 '13 at 13:13
  • I agree if you are going to use it in outer scope, but the question doesn't mention using result of linq sentence in outer scope. – Esteban Elverdin Jan 15 '13 at 13:22
  • There is `return qry.ToList()` so it looks like will be used in outer scope. – mipe34 Jan 15 '13 at 13:25
  • @mipe34 Though I'm personally not a fan of this, but you can write the query above in the following method: private dynamic GetList() { ... } – Laszlo Boke Jan 15 '13 at 13:31
  • Right, I think I understand the meaning of the question now. I guess you can write the answer. – Esteban Elverdin Jan 15 '13 at 13:33