tags:

views:

69

answers:

3

Using Linq I would like to return an object that contains customers and invoices they have.

I understand returning a single type from a method:

public IQueryable<customers> GetCustomers()
{
    return from c in customers
           select c;
}

But I am having trouble figuring out multiple objects:

public IQueryable<???> GetCustomersWithInvoices()
{
    return from c in customers
           from inv in c.invoices
           select new {c, ci}  // or I may specify columns, but rather not.
}

I have a feeling I am approaching this the wrong way. The goal is to call these objects from a controller and pass them up to a view, either direct or using a formViewModel class.

+1  A: 

You cannot return an anonymous type from a function, they are strictly "inline" classes. You will need to create a concrete type to hold your members if you want to encapsulate them in a function.

Using a view model, as you mentioned, would be a good place to put them.

Here is a scottgu article about anonymous types. From the conclusion of the article:

Anonymous types are a convenient language feature that enable developers to concisely define inline CLR types within code, without having to explicitly provide a formal class declaration of the type. Although they can be used in lots of scenarios, there are particularly useful when querying and transforming/shaping data with LINQ.

There's some good discussion in the comment thread on that page.

magnifico
Technically you could make the return type of the function either `object` or `IEnumerable<object>` and it would work. Whether you could do anything useful with the result is debatable, though.
Joel Mueller
That is exactly what I am struggling with. I simply want to query customers and invoices out of a database, send them up and iterate them out to a web page; this should not be complicated.
Brettski
+1  A: 

In the second case you are creating an annonymous type which has method scope. To pass an annonymous type outside the method boundary you need to change the return type to object. This however defeats the purpose of the annonymous type (as you lose the strong typing it provides) , requiring reflection to get access to the properties and their values for the said type.

If you want to maintain this structure as your return type you should create a class or struct consisting of properties to hold the customer and invoice values.

Simon Fox
That makes sense, now for a name...:)
Brettski
I created a class which is being returned as list<MyClass>. I don't like it though, I would just rather return an object and use customer.invoices.invoiceid, etc to get at the data. This seems to messy.
Brettski
You should be able to do it that way anyway. You will just have to specify a DataLoadOptions when opening your DataContext to include invoices when loading customer objects. See http://msdn.microsoft.com/en-us/library/system.data.linq.dataloadoptions.loadwith.aspx
Simon Fox
A: 

If you really want to, you can do this, but it is rather awkward.

public IQueryable<T> GetCustomersWithInvoices(T exampleObject)
{
return from c in customers
from inv in c.invoices
select new {c, ci} // or I may specify columns, but rather not.
}

var exampleObject = new {
Customer c = new Customer(),
Invoice i = new Invoice()
};

var returnedObjectOfAnonymousType = GetCustomersWithInvoices(exampleObject);

In this way, you can take advantage of type inference to get your method to return an anonymous type. You have to use this ugly method of passing in an example object to get it to work. I don't really recommend that you do this, but I believe that this is the only way to do it.

Brett Widmeier