LINQ and dynamic Query Results?
I've been mostly watching LINQ take shape and only recently started in looking at it a bit more closely.I've been pretty excited about the prospect of LINQ in general and the database connectivity in particular - after all I come from an XBase background where a built in Data Definition Language and native SQL syntax has always been available (for 20 years!). LINQ of course is much more than just the data access layer and to be honest the language integration features are much more impressive than the data possibilities.
Disclaimer: I'm just starting to look at LINQ to Entities stuff, so it's quite possible I'm missing some of the picture - I'm throwing out some of the impressions and questions I have from what I've read, tried and heard from various speakers.
Last week at the MVP summit, Anders Heljsberg went through a quite extensive demo of various LINQ features and it was just one more kick in teh ass for me to take a closer look. However, after seeing Ander's demo and hearing some of the comments made, and asking a few questions regarding LINQ there's one issue that really gnaws at me and that's the issue of anomyous types travelling well across local method boundaries such as returning a dynamic query result from a method.
I'm not 100% sure I understand all the issues here, but apparently one issue of LINQ is that you cannot run 'dynamic' queries - queries that return anonymous types - and return the result back out of a method in a meaningful way. So if you do something like this:
public static void WebStore101()
{
WebStoreDataBaseDataContext db = new WebStoreDataBaseDataContext();
var q = from c in db.Customers
from i in db.Invoices
where c.company == "West Wind Technologies"
where c.pk == i.custpk
where i.invdate > DateTime.Now.AddMonths(-5)
select new { c.company, c.lastname, c.pk, i.invdate, i.invtotal };
ObjectDumper.Write(q, 0);
}
where the select clause basically creates an anonymous type on the fly, there's no good way to pass out the var q result. You can't define a method to return of type var as far as I can tell. You can return the type as a generic object. So return q can be returned generically only as type object or IEnumerable when the type is anonymous.
So we have duck typing but no way to waddle our way out of the local scope <s>.
This makes perfect sense in a strongly typed environment I suppose - the specifications for the anonymous type are bound up within this local method and outside of that method nothing can really know what the type of the created object is. But nevertheless from a re-usability point of view we have a big problem if you want dynamic results.
What’s a bit infuriating about this is – we’re so close yet not quite there! You can force a projection to be identified with a type name by using the into clause. For example to return both the invoice and customer data in a local method you can use code like this:
var q = from c in db.Customers
from i in db.Invoices
where c.company == "West Wind Technologies"
where c.pk == i.custpk
where i.invdate > DateTime.Now.AddMonths(-5)
select new { c, i, c.lastname, i.invtotal} into x
select x;
foreach (var x in q)
{
Console.WriteLine(x.c.company + " - " + x.c.lastname + " - " +
x.i.invdate.ToString() + " - " + x.i.invtotal.ToString());
}
So within the local method you can get this duck typing to work through projection, but unfortunately ‘x’ in this case is a local only variable. It sure would be nice if there was some way to define a public type…
The above only applies if you’re using anonymous types. You CAN return query results if you run the results into a specific enumarable type which means using the select clause and inserting into an existing type:
public static IEnumerable<Customers> WebStore101()
{
WebStoreDataBaseDataContext db = new WebStoreDataBaseDataContext();
IEnumerable<Customers> q =
from c in db.Customers
from i in db.Invoices
where c.company == "West Wind Technologies"
where c.pk == i.custpk
where i.invdate > DateTime.Now.AddMonths(-5)
select c;
ObjectDumper.Write(q, 0);
return q;
}
the result q in this case is a concrete enumaration and that can easily passed out of the method. But if you do this you're also not getting any of the related data - the invoice data in this case since the type you assign has to be a single type. IOW, this completely changes the nature of the query...
The other problem with concrete class implementations – unless you create specific classes for every possible query result – is that you end up with a lot more data than you might be asking for. If you run say: select c.pk, c.lastname and you project it into a full customers object you’ll get the entire customer data instead of just the pk (although single values can be cast directly to their structural type with LINQ, so maybe that’s a bad example – take two fields instead).
What works and what doesn’t?
If you're going to end up using LINQ queries right in the UI layer and databinding the data directly to a DataSources there's not much of a problem. The DataSource controls understand and can bind to the data no problem because they are already using Reflection to dynamically figure out what fields need to be bound etc.
DataSource controls appear to also understand the object structure if you return a dynamic query result as IEnumerable or object, because they essentially look at the object structure via Reflection.
But I’m seriously wondering how can I use LINQ in my business layer and pass the results I might get back from a dynamic query back up to another application layer like the UI. And say the UI layer needs to iterate over the data manually to perform some calculation. This doesn’t appear to be an option…
Am I missing something really obvious here? This seems like a major limitation of LINQ.
Other ways to query?
So while looking at this I started experimenting around with a number of different ways to query the data and try to return results back. As I mentioned earlier you can return a dynamic query result as object or IEnumerable. Not terribly useful but it works with databinding.
One thing that does work is to create a custom time and then have LINQ project the result into a custom type. So if you run a query and you have a couple of dynamic fields you can create a public matching class and dump the data into that. It’s pretty cool that you can do this, but it begs the question – why isn’t there some way that the compiler can’t do this for me with the into (or some other directive):
public class WebStoreDataTest
{
public static IEnumerable<SqlResult> WebStore101()
//public static void WebStore101()
{
WebStoreDataBaseDataContext db = new WebStoreDataBaseDataContext();
// use Where() to find only elements that match
//IEnumerable<Customers> q = db.Customers.Where(c => c.company == "West Wind Technologies");
//IEnumerable<Customers> q =
IEnumerable<SqlResult> q = from c in db.Customers
from i in db.Invoices
where c.company == "West Wind Technologies"
where c.pk == i.custpk
where i.invdate > DateTime.Now.AddMonths(-5)
select new SqlResult(c.company, c.lastname);
ObjectDumper.Write(q, 0);
return q;
}
}
public class SqlResult
{
public SqlResult(string Company, string LastName)
{
this.company = Company;
this.lastname = LastName;
}
private string _company;
public string company
{
get { return _company; }
set { _company = value; }
}
private string _lastname;
public string lastname
{
get { return _lastname; }
set { _lastname = value; }
}
}
This works great – I get a strongly typed object, but then we're back into the same mess that we've always had with Entity object frameworks where every kind of query requires a custom object to load the data into.
It sure would be nice if the into clause could somehow create a public object (optionally) - after all the compiler is already doing the hard part of creating the types in the first place...
So what?
LINQ looks just awesome (not just for the Data access stuff, but for the base language), but this issue has me pretty worried about just how useful LINQ is going to be inside of a business layer.
Anybody been thinking about this issue? I can’t be the first one who’s hit this and trying to analyze the implications.
The Voices of Reason
# re: LINQ and dynamic Query Results?
http://tomasp.net/blog/cannot-return-anonymous-type-from-method.aspx
# re: LINQ and dynamic Query Results?
Using the new automatic properties support, this is really easy to-do, and allows you to serialize them automatically across web-services. For more on automatic properties, please read this: http://weblogs.asp.net/scottgu/archive/2007/03/08/new-c-orcas-language-features-automatic-properties-object-initializers-and-collection-initializers.aspx
If you want the access to be completely late-bound, then you can either return an IEnumerable or Object and use reflection against it. Or alternatively, you can can save the results of the LINQ query in a hash lookup-like structure like a DataTable/DataSet.
In fact, you could even write an Extension Method for DataTable that automatically loaded the result of a LINQ query into a DataTable for you if you wanted to:
DataTable result = new DataTable;
result.Load(q);
You could then access the values using the row and columns API for a DataTable. For more on extension methods, please read this: http://weblogs.asp.net/scottgu/archive/2007/03/13/new-orcas-language-feature-extension-methods.aspx
Hope this helps,
Scott
P.S. I have some good
# re: LINQ and dynamic Query Results?
[code=C#]
IEnumerable<R> GetCustomers(Func<X, R> selector) {
var results = from .......
select selector;
return results;
}
// And then call it like:
var customersWithNames = GetCustomers(c => new { c.Name });
var customersWithNamesAndAge = GetCustomers(c => new { c.Name, c.Age });
[/code]
# re: LINQ and dynamic Query Results?
I can see the definition of a CustomerInvoiceData query result object and feeding that as I did in one of the examples, but man you are going to end up with a lot of objects littered in your application if you do this. Not only that, but sometimes the results are truly dynamic where users can pick what fields they want to return support. I suppose in that case the Hashtable like interface would work. I have to check that out...
It just seems that this is really unnecessary, if the compiler could just spit out a globally accessible object instead of a local one. I suspect it's difficult for the compiler to track this object reference, but honestly if you think about usage scenarios this is a pretty big deal.
Nobody wants to go back to using a DataTable or Hashtable with object lookups when the whole promise of LINQ is strongly typed querying and results. <s>
Wilco, hmmm... interesting idea, but aren't you in effect then making the projection local to the caller? Then the target method can't see the anonymous type properly. I have to play with this as well.
I think the big issue for business object methods is this: Whatever you return from a business object method needs to be easy to use. In the business layer maybe more work is reasonable, but not when the data comes out of it. To me that means that if the LINQ query comes back it should be visible with standard LINQ object semantics. If it's anything else I might as well continue using a DataTable/DataReader etc. and truly consider LINQ just a tool for 'local' method processing.
# re: LINQ and dynamic Query Results?
[code=C#]
IEnumerable<R> GetCustomers<Func<X, R> selector) {
var results = from c in Customers ... select new { c.Name, c.Age };
// Do something with results if you want...
foreach (var r in results) {
// X is inferred from the dynamic type in this method, R is inferred from
// what happens inside the selector.
yield selector(r);
}
}
[/code]
What you're suggesting seems rather scary. I don't think you want the compiler to be in the business of generating *user* types. As soon as it does that, you and the compiler will have to start dealing with conflicts, etc. You'd end up with a complete mess.
# re: LINQ and dynamic Query Results?
select { c.company, i.invdate } into ResultQuery as CompInvoiceThe compiler could just as easily create a class with that type name as it does now with 'generated' type name. Operationally that doesn't change anything. The compiler semantics would be more difficult no doubt but from a compiled code perspective what's really different other than that the type has now a known and reusable name you can reference?
I would see this as an optional directive where the type gets generated into the current namespace (or you could provide it: MyNamespace.CompInvoice).
Remove Comment
# re: LINQ and dynamic Query Results?
Not sure how well that would work wrt. versioning though. Changing the projection directly changes the type, which might not be as obvious as changing a normal type.
(By the way, what's up with your blog? Every post so far I had to repost because I got a server error.)
# re: LINQ and dynamic Query Results?
What exactly are your concerns regarding versioning?
As to the errors - I have to check the error log and see what's going on. I've been replying to your comments with no problems, but then my posting path's a little different than your's <s>. Will check it out. Maybe I should start using the same mechanism as everybody else once in a while, he he...
# re: LINQ and dynamic Query Results?
# re: LINQ and dynamic Query Results?
If you really want strong type validation then Scott's suggestion of creating an explicit query result type works. The issue with this is that you get a lot of clutter in your projects for these types and it's not exactly quick to create a new class, properties (easier in 3.5 thankfully though) and a constructor to make this work. You now also have to make changes in two places everytime you change a query, which is the real bummer.
I mean even a simplistic application like this Web Log probably has a hundred different custom query results - imagine creating all those types for each result manually. OTOH, I wonder what this does to application performance - all those dynamic types have to exist somewhere. All of a sudden you end up bloating your assemblies and memory footprint something fierce for all these dynamic types.
# re: LINQ and dynamic Query Results?
Although I find Wilco's suggestions smart (as his code usually is ;) ), one thing I don't like is that the method doesn't expose its return type. The user code needs knowledge of the inner workings of the method to decide how to write the lambda function. I'm not even talking about how you document that and explain why it's necessary to jump through those loops. Nice workaround though.
# re: LINQ and dynamic Query Results?
[code=C#]
IEnumerable<TCustomerProjection> GetCustomers<Customer, TCustomerProjection>(Func<Customer, TCustomerProjection> selector) {
// ...
}
[/code]
This should make it much more accessible... But yeah, being able to name a type which would otherwise be anonymous would probably be ideal.
# re: LINQ and dynamic Query Results?
But maybe you guys inside of the hive can run that by some people of influence. This seems totally doable and a huge usability improvement...
# re: LINQ and dynamic Query Results?
Dody has a post on the topic ""LINQ Data Layer Pattern - Why it sucks" http://spellcoder.com/blogs/dodyg/archive/2007/03/19/6389.aspx
The inability to return an instance of an anonymous type might sound logical, still is quite annoying.
The solution Scott Gu suggested (Scott Gu is my favourite hero BTW) is not that good though. I won't discuss why we have those originally. I again agree with Dody that "C# 3.0 Automatic Properties is a hack" (check http://spellcoder.com/blogs/dodyg/archive/2007/03/09/6191.aspx ). However, the real problem is that you end up having too many junk types, each per each series of data columns or anonymous type property, which is bad bad.
Dody suggested that C# 3.0 should support Taples. Personally I'm not sure whether this is the right answer, or this should be supported in C# 3.0 not 3.x or so, but I can't see more alternatives. The idea to return Object or IEnumerator is needless to say another bad bad bad thing I guess! Also, using a single type per entity and filling only the properties you return is a non typed method of doing it (you keep womdering which properties have values), and leads to many other odd questions.
# re: LINQ and dynamic Query Results?
# re: LINQ and dynamic Query Results?
# re: LINQ and dynamic Query Results?
I had the exact same experience as u do and then I found this article.
What we have decided in our developments is to avoid using projections when u returning from a Business Layer/Data Layer. We jsut stick to the selection of the entities like:
public IQueryable<Customer> GetCustomers()
{
NorthwindDataContext db = new NorthwindDataContext();
var query = from c in db.Customers
select c;
return query;
}
The calling environment is then responsible of doing any projections by adding another linq expression on top of the returned results like:
static void Main(string[] args)
{
var customers = GetCustomers();
var customerContacts = from c in customers
select new { c.CustomerID, c.ContactName };
foreach (var customerContact in customerContacts)
{
Console.WriteLine(customerContact);
}
Console.ReadKey();
}
hope this helps. :)
# re: LINQ and dynamic Query Results?
# re: LINQ and dynamic Query Results?
Also remember that in most cases queries will be more complex, but as a general practice in a business layer I prefer abstracting every query into the middle tier no matter how simple. For one thing it makes it much easier to get a feel of what code is accessing the database and what it's doing.
This post http://www.west-wind.com/WebLog/posts/159522.aspx on creating a LINQ business layer outlines some of the reasons along with code on the whys and hows of doing this.
# re: LINQ and dynamic Query Results?
My personal solution, for the time being, is to create database views for the select statements that would otherwise produce anonymous types. I add the views to the LINQ designer and voila, I get a first rate class and loss the anonymous type issue. Of course, if designed carefully, views are also updateable.
This does not solve the problem of adhoc type queries but does make life generally easier and seems like a reasonably 'pure' solution.
I realize this thread is not very current, hopefully my comment is still useful.
# re: LINQ and dynamic Query Results?
The is a dynamic linq sample that I have been playing around with that lets you specifiy your queries as follows.
var query =
db.Orders.Where("ShipCountry == @0", "USA").
OrderBy("Customer.CompanyName, OrderDate").
Select("New(Customer.CompanyName as Company, ShipCountry, OrderDate, ShipName, Order_Details.Average(UnitPrice) as Crap, Order_Details.Average(Quantity) as MoreCrap)");
Notice the column definition for the select is a string that gets parsed by the Dynamic Linq extension. I can then access the dynamic class that is returned any way I chose, for instance
foreach (object c in query)
{
PropertyInfo[] infos = c.GetType().GetProperties();
foreach (PropertyInfo info in infos)
{
Console.WriteLine("{0} = {1}", info.Name, info.GetValue(c, null));
}
}
This way you don't have to define an huge number of GetCustomer functions with every column combination.
# re: LINQ and dynamic Query Results?
http://www.west-wind.com/WebLog/posts/143814.aspx
# re: LINQ and dynamic Query Results?
# re: LINQ and dynamic Query Results?
var data = from c in context.Customers select new { c.FusrName, c.LastName } into BLL.CustomerName;
The compiler is already smart enough to reuse anonymous types as well ... but not smart enough to reuse if the properties are re-arranged ... (that could be an improvement)
The main challenge really is during design-time ... the intellisense would need to pre-compile anonymous types on the fly to determine properties ... it would have to look at the return type of the function ... which also raises the issue, what if the funtion returns two diff anonymous types via conditional statement?
A more crazy approach would be to introduce the ability to define properties on the fly ... i kinda like ActionScript approach where you can use the dynamic keyword in the class header
dynamic class Whatever
{
}Then the calling code can define and read properties on the fly ...
Whatever obj = new Whatever(); obj.FirstName = "Mike"; if(obj.FirstName) Console.WriteLine(obj.FirstName);
All anonymous types would define a class in this mode ... of course you lose early bound features (including intellisense) ... but at least then you could return anonymous type ... or plain object type ...
I guess no different from VB.NET w/ Option Strict off ... otherwise i presume you would have to beef-up the function prototype ... or maybe add more constraints to generic type definition ...
public List<T> GetCustomers() where T: { FirstName:string, LastName:string } { var data = from c in context.Customers select new T(c.FirstName, c.LastName); return data.ToList(); }
This approach obviously will get ugly and your basically near creating cutom business objects for every projection again ...
Finally, what really is the difference if we litter our library w/ all these business objects anyhow ... the compiler will do the same in the long run giving u less control ... so we come full circle ...
public List<CompanyName> GetCustomers() { var data = from c in context.Customers select new CompanyName(c.FirstName, c.LastName); return data.ToList(); }
If we aready have the business oject created maybe we can shorten this to save typing ...
public List<CompanyName> GetCustomers() { var data = from c in context.Customers select as CompanyName; return data.ToList(); }
But would require more compiler involvement ...
# re: LINQ and dynamic Query Results?
# re: LINQ and dynamic Query Results?
And there's also the issue of having to use Reflection to do the update which is relatively slow.
# re: LINQ and dynamic Query Results?
# re: LINQ and dynamic Query Results?
http://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/66067ca2-7cdf-403c-ab8e-aebe8ff166db
# re: LINQ and dynamic Query Results?
I almost always agree with you on topics what do you think of my opinion on LINQ/Lambda?
http://softwaresense.blogspot.com/2010/06/linq-and-lambda-suck-yes-they-really-do.html
# re: LINQ and dynamic Query Results?
Great post. I've been trying to sort this issue out for some time. Sad thing is that you posted this over three years ago, and things don't look any better today.
Have you found any improvements in the last three years, or are we still stuck at the same place as we were when you wrote this?
Thanks again
# re: LINQ and dynamic Query Results?
ie. pass your changed object to a webservice and then try to call 'update' on it.
So, I think it needs work there, otherwise, it's just a 'logical' multi-tier environment