Update 2 : @Enigmativity has a brilliant answer. I\'ve implemented this into a IObservableRepository
. Details in my answer below.
Just a quick, off the cuff answer.
How about using the Reactive Extensions for .NET (Rx)?
You could then define your repository as:
public interface IObservableRepository<T> where T : class
{
IObservable<T> GetById(int id);
IObservable<T> GetAll(Func<IQueryable<T>, IQueryable<T>> query);
IObservable<Unit> InsertOnSubmit(T entity);
IObservable<Unit> DeleteOnSubmit(T entity);
IObservable<int> SubmitChanges();
}
All of the returned observables would contain single values, except for GetAll
which would have zero or more.
The Unit
type is void
in the Rx world. It's just a way of not needing to define a non-generic IObservable
interface.
You would then query like so:
IObservableRepository<Foo> repo = ...;
var foos = repo.GetAll(ts => ts.Where(t => t.Bar == "Hello"));
foos.Subscribe(foo =>
{
// Do something asynchronously with each `Foo`.
});
And submit could be done like this:
var submit =
foos
.Select(foo => repo.InsertOnSubmit(foo)).ToArray()
.Select(s => repo.SubmitChanges());
submit.Subscribe(result =>
{
// handle the asynchronous result of submit.
});
This is all based on trying to keep the repository methods as close as possible to the original, but it may be worth refactoring on the Silverlight side to something like this:
public interface IObservableRepository<T> where T : class
{
IObservable<T> GetById(int id);
IObservable<T[]> GetAll(Func<IQueryable<T>, IQueryable<T>> query);
IObservable<int> Submit(T[] insertsOrUpdates);
IObservable<int> Submit(T[] insertsOrUpdates, T[] deletes);
}
Submit would be a bit nicer now:
repo.Submit(foos).Subscribe(result =>
{
// Handle asynchronous result of submit;
});
Like I said, off the cuff. :-)
Too long to update the question, so I posted as an answer.
So I implemented it like this:
public interface IObservableRepository<T, TContext>
{
IObservable<T> GetById(int id);
IObservable<IList<T>> GetAll(Func<TContext, IQueryable<T>> funcquery);
IObservable<int[]> SubmitInserts(IList<T> inserts);
IObservable<int[]> SubmitDeletes(IList<T> deletes);
IObservable<int[]> SubmitUpdates(IList<T> updates);
//helpers
IObservable<int> SubmitInsert(T entity);
IObservable<int> SubmitDelete(T entity);
IObservable<int> SubmitUpdate(T entity);
}
Some notes :
TContext
is needed for GetAll()
, the implementation will have the Entity Framework DataServiceContext
which will allow you to do the following:
var foos = repo.GetAll(ts => ts.Where(t => t.Bar == "Hello"));
//ts is a DataContext passed here by GetAll();
//helpers
just call the other methods that take arrays.DataServiceResponse
. What I do is loop through them and return the Http Status Codes. So the ints returned for the CRUD methods are Http Status Codes.When loading child entities I just eager loaded them by doing this:
context.Products.Expand("Child").Expand("Child2");
I can basically use it like this:
productRepo.GetById(3).Subscribe(x => /* Do something with product x*/ );
productRepo.SubmitUpdate(product)
.Subscribe(r => /*return code should be 204 (http) 201 for insert */);
//same for insert and delete
Do tell me if I should put up the actual implementation here.
Any comments on this would be well taken =)
Thanks