Thursday, September 27, 2007

Updatable, inheritable, WPF bounded Linq queries

This is part 4 of my "binding Linq to Xceed's data grid" blog series; however I've changed direction dramatically.

Skipping the details, heres the code binding to a linq query:

users.LinqContext = new UserDataContext();

users.ItemsSource = from i
in users.DataSource<User>()
select i;


And this code fully supports inserts/updates/deletes.

The implementation lives inside the DataSource<User>() call. This devious character returns a reference to a IBindingList (which supports the table modifications) and implements IQueryable (to support linq queries).


What about inheritance?

Imagine you had a sub class called SuperUser; if you've played with linq inheritance you'll know that you have to use the base type User to actually do anything. It's kind of a pain, and you get real friendly with the .OfType<>() call.

So here's the code again, this time selecting all SuperUsers.


users.ItemsSource = from i
in users.DataSource<User, SuperUser>()
select i;


Can I use .Take(x)?

As far as I can tell, all the standard linq statements are supported (including aggregate operators). I haven't looked into partial classes and anonymous types, though I doubt they'd work well.


I won't go into the laborious details of how it's all implemented, just know that it's been fun playing with linq expression trees and writing my own IQueryProvider.

If you are interested, the code can be found here.

I haven't seen anything quite like this out there, so if you have some opinions - I'd love to hear some feedback.

13 comments:

Nick said...

Quick Q - apologies for the laziness :)

Why are you rewriting the expression tree?

Luke Marshall said...

I'm not actually rewriting the expression tree, rather injecting and wrapping it.

This way I can return my own BindingList (which supports inserts/updates/deletes) instead of the direct database collection.

Anthony said...

Luke,

Have you ever tried your solution with groupings?
If so, did you manage to insert new rows without any errors?
I keep getting an unhandled DataGridInternalError. I think it occurs when the layout gets refreshed, cause all data inserted well.
Any help or ideas would be appreciated.

Luke Marshall said...

Great question Anthony!

I haven't tried it with the linq "group by" - but I don't think it would work well (considering two-way binding).

However I have successfully used the ICollectionView grouping features.

Which one are you trying? or have you another option?

Anthony said...

Luke,

It works, I found was I was doing wrong.
My grid is not enabled, additions and changes are managed by a detailed page with fields binded to the currentitem in the grid.
What I forgot was setting the insertionrow in the fixedheaders.
Problem solved.
Thanks for your response.

Luke Marshall said...

Glad to hear you got it working.

Cheers!

Anonymous said...

how can add validation ?
every time i validate its break down at endedit

Anonymous said...

i cant insert new records
the cell is disabled
what is wrong :(

Luke Marshall said...

Hi anonymous!

For validation I would suggest using the Xceed validation classes (since IDataErrorInfo is not supported yet).

The validation classes throw exceptions at EndEdit, but if you ignore this the validation error kicks in.

As for the disabled cell, I really can't help without more information.

Luke Marshall said...

Oh and change this in DataBindingList.cs to fix a small bug.

protected override void RemoveItem(int index)
{
if (((index >= 0) && (index < base.Count)) && (base[index] == this.cancelNewInstance || base[index] == this.addNewInstance))
{
this.addNewInstance = default(TEntity);
this.cancelNewInstance = default(TEntity);
}
else
{
this.table.DeleteOnSubmit(base[index]);
}
base.RemoveItem(index);
}

Anonymous said...

hi
i am using xceed validation that throw exception but after that endedit fail at LinqDataRow class
thanks

Anonymous said...

Luke,

Sorting not working

Luke Marshall said...

Not sure what's wrong with your validation - it seems to work fine for me.

Yes sorting isn't working, feel free to have a crack at it!

I stopped updating this code about a year ago when I found BindableLinq - I'm not sure if it's a complete replacement, but it looks pretty good!