The World’s Leading Microsoft .NET Magazine
   
 
The .NET Addict's Blog

My Top Tags

                                                           

My RSS Feeds








Latest Diggs - Programming

Internet Blogs - Blog Top Sites

Site Hits

Total: 2,551,710
since: 19 Jan 2005

Dynamic, Observable LINQ Views

posted Mon 30 Jul 07

In case you aren't already aware, LINQ (Language INtegrated Query) is a new feature coming out of the .NET Framework 3.5. It allows you to query everything from in-memory collections of objects to remote data stores with syntax that looks like this:

var q = from cust in Customers
    where cust.Age > 21
    orderby cust.CustomerName
    select cust;

The Problem

The great thing about LINQ is that it gives you a natural expressiveness that you can use to describe the data you're looking for. The problem with it is that what you get back is stagnant. This means that while you might get rows once you ask q for it's enumerator (how fetches are triggered in LINQ), you're going to get a result set that doesn't change. So that means that if someone goes and adds a couple of customers to your original source (this is quite common for networked desktop applications to receive "model updates" from network messages), you're going to have to re-run (re-enumerate) your query to see the new changes. To me, this is unacceptable.

The Solution

The way it should work is that when someone adds or removes customers from the underlying store, the result set that you obtained should also be modified. When a customer is added to the backing store, it should be re-evaluated against the membership predicate (the clause you specified in the where statement) and if it passes, it should be added to your result set automatically. Likewise, if a property changes on any of the customers currently residing in the backing store, those customers should be re-evaluated against the filter predicate and added to the result set if they now pass the test. For example, let's say your query starts out with 5 items. Then, someone adds a customer to the backing store that is 22. You should now have 6 items in your result set without having re-queried or re-polled. Next, someone changes the age of a 15-year-old customer to 27. This customer now qualifies to be in your result set. As a result, that customer is automatically added to your result set without you having to do anything to make it happen. Finally, each time the result set is modified, the sort is re-evaluated so that if someone changes a customer's name, the sort order of the customer list is re-evaluated so that it stays consistent with the key selector you specified in the orderby clause.

This is exactly what I've done with a language extension that I've written for a class that I've had lying around for a while, a ThreadSafeObservableCollection<T>. This class is really just a descendent of ObservableCollection<T> with some thread-safety semantics bolted on top. Now, anytime you run a LINQ query against this class, you get a live, connected, dynamically updating result set that is notified of all changes to the backing store and updates itself accordingly. I don't have group-by working yet, but I've got sorting and filtering (orderby and where).

Take a look at the following code:

customers = new ThreadSafeObservableCollection<Customer>();
Customer c = new Customer("Bob", 21, 50.00f);
customers.Add(c);
Customer c2 = new Customer("Alice", 30, 156.00f);
customers.Add(c2);
Customer c3 = new Customer("Joyce", 53, 121.00f);
customers.Add(c3);
var query = from cust in customers
            where cust.CustomerName.Length > 3
            orderby cust.CustomerName descending
            select cust;

this.DataContext = query;
Customer c4 = new Customer("Jen", 18, 324.00f);
customers.Add(c4);
Customer c5 = new Customer("Aaron", 54, 123.00f);
customers.Add(c5);
c.CustomerName = "Super Bob";
customers.Remove(c4);

Now, without the language extension, all changes made to the c4 and c5 customers will be ignored by the GUI, and the will not know that the c4 object has been removed. Finally, changing the name of the first customer in the list will go unnoticed (remember that I'm changing the backing store and not the result set!). Additionally, the sort order won't be re-evaluated. You'll have to re-request the enumerator for the query variable to get it to update.

With the language extension that I've written (inspired by the work done at SLINQ, though this particular extension doesn't require a polling timer to see the data and has been written specifically to take advantage of standard classes already in the framework) you can see that not only are the additions made to the backing store reflected by the GUI, but the sort order specified by the query is also respected...live...without requerying.

I'll eventually be posting more of the code for the language extension once it gets tidied up. The names of the classes in the library are still kind of up in the air (they're currently too long), and I need to add support for group by and then come up with a bunch of test case LINQ queries to exercise the library with some edge cases. Once I get to that point, I'll post again with some more code. If anybody can think of a good name for this stuff (I'm thinking of calling it Dynamic LINQ Views, but I'm not sure), I'd apprciate the feedback.

Enjoy!

tags:        

links: digg this    del.icio.us    technorati    reddit




1. Maercu left...
Tue 31 Jul 07 5:35 am

Hmm, since there's still no comment saying just that: Congratulations, it seems you've understood the real world problem ;-) Continue the good work, I might be really interested in your findings and code if one day we move over to .net 3.5 (or higher) with our .net 2.0 solution.


2. Kevin Hoffman left...
Tue 31 Jul 07 6:26 am

Thanks.. I'm glad someone noticed the real-world solution I'm working on here... it's going to come in immensely handy for future applications. The code I've got is really quite basic, but once I get it a little shinier I'll start posting the source to the language extension and the supporting classes.


3. Jordan Vinarub left...
Tue 31 Jul 07 12:16 pm

I think Anders and Microsoft owes you $5 for making LINQ worthwhile.


4. Kevin Hoffman left...
Tue 31 Jul 07 1:40 pm

I do this and all I get is $5?? :)


5. Karl Ebersbach left...
Wed 01 Aug 07 1:05 pm

Thanks for alll your efforts! I'm really looking forward to using this!


6. David Cumps left...
Wed 22 Aug 07 3:36 pm :: http://blog.cumps.be

Wow, that's really valuable for financial GUI's, where prices keep on changing.

Slowly reading your posts, to check if there's more about this already :)


7. Ben Stabile left...
Fri 21 Dec 07 4:42 pm

I extend with SQL Server Service Broker and call it "LINQ Sync".


Tag Related Posts

CLINQ v1.1.0.0 Released!

Fri 02 May 08 5:38 P GMT-05
tags:          

LINQ to REST - A much better name for Astoria

Tue 11 Dec 07 1:23 P GMT-05
tags:        

Unexpected and Unsafe behavior in LINQ

Wed 14 Nov 07 8:09 P GMT-05
tags:    

C# 3.0 - Are Object Initializers Evil, Useful, or Both?

Fri 26 Oct 07 10:53 A GMT-05
tags:    

Continuous LINQ - Can I write games with it?

Mon 13 Aug 07 3:09 P GMT-05
tags:        

Silverlight 1.1 Alpha Refresh

Fri 10 Aug 07 2:09 P GMT-05
tags:    

Orcas Beta 2 - might as well be a CTP

Tue 07 Aug 07 1:15 A GMT-05
tags:  

Continuous LINQ

Mon 06 Aug 07 1:21 P GMT-05
tags:    

Dynamic, Observable LINQ Views

Tue 31 Jul 07 1:21 A GMT-05
tags:        

Acropolis or Acrapolis?

Thu 05 Jul 07 12:34 P GMT-05
tags:      

My first "Acropolis" Application

Mon 04 Jun 07 1:40 P GMT-05
tags:      

Orcas' Hidden Gem - The managed PNRP stack

Fri 11 May 07 6:45 P GMT-05
tags:        

Orcas EDM Wizard Patched

Fri 27 Apr 07 11:56 A GMT-05
tags:      

Installing Orcas Beta 1 - VMware Style

Mon 23 Apr 07 12:16 P GMT-05

Orcas Beta 1 Released

Fri 20 Apr 07 7:09 P GMT-05

Visual Studio "Orcas" - March CTP is Available

Wed 28 Feb 07 12:28 P GMT-05
tags:            

Objective-C Categories vs C# 3.5 Language Extensions

Mon 26 Feb 07 1:05 P GMT-05
tags:                

DLinq vs the ADO.NET Entity Framework

Fri 23 Jun 06 4:01 P GMT-05

WPF/XAML and LINQ - A match made in heaven

Tue 06 Jun 06 11:32 A GMT-05
tags:                  

Language Extensions in C# 3.0

Wed 31 May 06 2:17 P GMT-05

Lambda Lambda Lambda

Sun 21 May 06 1:01 A GMT-05

The Adventures of LINQ (Not Zelda)

Fri 19 May 06 11:21 P GMT-05
tags: