tags:

views:

57

answers:

3

Hello,

I've usually have difficulties with return types when it comes to linq. I'll explain by the following examples. Let's say I have a Table Products with ProductID, Name, Category, and Price as columns :

1) IQueryable<Product>

public IQueryable<Product> GetChildrenProducts()
{
  return (from pd in db.Products
          where pd.Category == "Children"
          select pd);
}

2) Product

public Product GetProduct(int id)
{
  return (from pd in db.Products
          where pd.ProductID == id
          select pd).FirstOrDefault();
}

Now, if I decide to select, for instance, only one column (Price or Name) or even 2 or 3 columns (Name and Price), but in any case, less than the 4 columns, what's going to be the return type?

I mean this:

public returnType GetSomeInformation()
{
 return (from pd in db.Products
         select new { pd.Name, pd.Price }
}

What SHOULD BE the returnType for the GetSomeInformation()?

Thanks for helping

A: 

Short answer: IEnumerable.

Long answer:

What you are returning is a collection of anonymous type, hence the need that the return type to be IEnumerable.

Paulo Santos
And how would you suggest to get to the property values of the untyped anonymous type? ( Don't say reflection ;-)
Yannick M.
That's one thing I simply **hate** in C# the lack of dynamic member resolution. VB.NET has this since .NET 1.0. It's iicsome. And now everyone is talking about *dynamics* like it were the second coming. Geez... it has been around for ages.
Paulo Santos
Tbh, I see the implementation of the DLR only as a means to an end. This allows me to do less irritating COM interop, and call on dynamic language resources. But I don't see myself using the `dynamic` keyword for much else.
Yannick M.
Of all reasons to use dynamic member resolution, this would be one of the worst. It would've been great if the type inference algorithm would allow you to return the typed result without declaring a class, though.
erikkallen
@erikkallen the thing is, Erik, VB has this kind of thing since VB 3 for Win 3.1, and VB.NET since 1.0. All resolution is done dynamically. Granted you can't create a new member as you can do with dynamic types, but you can call whatever existing member you want.
Paulo Santos
@Paulo - and that is one of the biggest problems many programmers have with VB. I personally can't stand that C# is adding dynamic types, there's no real need for it. I really hate var too, since too many lazy programmers have decided to just declare anything as a var, even when they know the exact type right away. Just look at just about any .Net tutorial or blog post - pure lazy coding.
Charles Boyung
+2  A: 

If you select multiple columns, but not the full object, LINQ returns a generic object. If you want to return that subset of data via a function, you need to create your own class and load it like this:

public class MyObject
{
  public string Name { get; set; }
  public double Price { get; set; }
}

public MyObject GetSomeInformation()
{
 return (from pd in db.Products
         select new  MyObject {
           Name = pd.Name, 
           Price = pd.Price 
         }).FirstOrDefault();
}
Charles Boyung
@Charles Boyung -- How about if I decide to query only one column (for instance, select pd.name). Do I need to create a class of one property? or I can use simple types, such as string, int, bool, etc.?
Richard77
Yes, if you just want a single column, then you can just use whatever .Net type the column is. If you are unsure, the VS intellisense for that column will tell you the type as you are writing the code.
Charles Boyung
+1  A: 

You cannot use var in this context, since type can currently only be inferred in local variables.

So either:

Move the Select() part to the caller, and return a plain IQueryable<Product>:

public IQueryable<Product> GetSomeInformation()
{
  return (from pd in db.Products
          select pd);
}

var information = GetProductInformation().Select(p => new { p.Name, p.Price });

Create a returntype ProductInformation which only contains the information you need:

class ProductInformation
{
  public string Name { get; set; }
  public decimal Price { get; set; }
}

public IQueryable<ProductInformation> GetSomeInformation()
{
  return (from pd in db.Products
          select new ProductInformation { Name=pd.Name, Price=pd.Price });
}
Yannick M.
@Yannick M. -- If I decide to query ProductID and Category (instead of Name and Price), do I need to create an other class containing the 2 columns?
Richard77
You could have your class contain all four fields if you wanted, and only set the fields you need to use, if you want. Or you could create multiple classes based on the fields you are returning for each LINQ request.
Charles Boyung
I prefer the first option, i.e. have only one class and set the fields I want. If That's true, (i) can I use Product instead of ProductInformation in the example above? (ii0 If I can use Product instead of ProductInformation, do I need 'Name = pd.Name' in place of just 'Name'?
Richard77
Also, from the above statement "var information = GetProductInformation().Select(p => new { p.Name, p.Price }", how can i use dynamic query (string) to replace "p => new { p.Name, p.Price" by a string. How do I do it?
Richard77
For that look into Dynamic Linq: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
Yannick M.