So in the last Rx article I talked about instant search. This article, we're going to go quite a few steps further and search an sql-compact-4 database asychronously! Thats right!
But! Its going to be a little head churner with lambdas and what nots, because we're going to encapsulate retreiving the data in a nice clean way(in my opinion)
You could also just:
What are we making:
You'll need the SQL CE Compact Toolbox because we are going to want an entity framework object context. (Which visual studio won't create for sqlce4 if its not a web project)
You'll also want the solution from the previous blog post on Rx.
Step 1 - Open the solution, open solution explorer (Ctrl + W, S). Right click the project and choose add new item. Select Data on the left and choose SQL Server Compact 4 Local Database (Phew!)
Step 2 - Its more easier to use Visual Studio's server explorer to create a new table. Open server explorer (Ctrl + W, L), it should show your database. (If it doesn't, right click connections and click add connection). Expand your database, Right click Tables and click Create Table.
Create a table like the following, note ID is an identity:
Step 3 - Throw in some data:
Step 4 - Add an entity model for your database. You'll need to have installed SQL Compact Toolbox, goto
Tools>Sql Compact Toolbox, Right Click your database and click Add Entity Data Model to current project.
We'll add two helper classes to abstract the task of searching our database asychronously with Rx.
So we're defining a method here that will be based on a Type T, which will be our entity object and TContext which will be the DataContext. This complete generic interface will help you later on when you want to mock and/or use DI. (I typically use MEF.)
We then implement it like so:
Notice, we'll use the
T at runtime so we can use this like a repository for any entity object.
Our one and only function
GetAllAsObservables, uses the
ToAsync method to convert the lambda passed as an argument, into a function which returns an
IObservable. We then make a call to this function
ToAsync(Database1Entities, IQueryable<T>) so
getall is a function that takes an instance of
Database1Entities and returns an
IObservable<T> which we transform/project into
Our MainForm code now looks like this:
First off, what we did last time was, we changed the
Textbox.TextChanged event to an observable sequence and throttled it by 500 milliseconds. So, our code got called by the system every 500ms, we then executed
DO every time this happened.
SearchList function does not search asynchronously, you could try and put
Thread.Sleep(5000) inside and it will block the UI.
So now!! We execute an async call through our little helper class, to search our database.
GetAllAsObservables() expects a lamba that takes our data context and returns an
IQueryable<T>, this means you can pretty much run any query against your context an long as it returns the right type. Also, this runs in the context of sql, not in memory.
We get in return an
IObservable<IList<T>> getfn. We then use
ObserveOn because we're going to touch UI from another thread. (This is equivalent to those
Invoke() calls you made in your old async code). This time on subscribe you are returned a an
IList<Customer>. The lambda you pass into
Subscribe is executed when the search is done async!
So try and run the code! Type in some names! =D
I hope this was useful, I'll take this further and get into how to properly abstract data access with Rx by creating Observable repositories. I've used these quite sucessfully in a number of apps!
Any critique, good, bad, ugly is welcome!