views:

85

answers:

1

I have a web service which provides an interface to query data. I am writing a WPF application using MVVM. I am working on creating a repository that my View Models can use to retrieve models. The repository will call the Web service to fetch data, when required.

I would require various Find methods in my repository that finds the data based on various criteria and not just one criteria like 'Id'.

In my Repository, I have created a Find method that takes a Specification as input

void IList<MyData> Find (ISpecification spec) 

where a basic ISpecification interface is

public interface ISpecification<T>
{
    bool IsSatisfiedBy(T candidate);
}

A high level implemenation of the Find method would be as follows

  • first searches the cache for candidates that satisfy specification
  • If found return the list of candidates
  • Else use the specification / criteria to call web service to fetch the candidates and return the list

I am confused about the Else scenario above - What is the correct way of designing the Specification so that if I have no data in repository cache that satisfies the specification, I should be able to retrieve the criteria from specification and call the web service passing the web method this criteria?

A few things on my mind-

  • If I specialize Find methods to take specialized specifications which have properties / criterias then Repository - Specification has tight coupling
  • If I would have to connect directly to DB (which I am not) then I could have supported a method that returns an SQL for example. LINQ could have been an option etc
+2  A: 

Why don't you use a linq expression as the parameter input?

e.g.

public class MyModel
{
  public int Prop1 {get;set;}
  public string Prop2 {get;set;}
}

public interface IRepository
{
  T Find<T>(Expression<Func<T,object>> expression);
}

public class MyRepository : IRepository
{
  public  T Find<T>(Expression<Func<T,object>> expression) where T : class
  {
    //Implement your caching/ calling your web service here
  }
}

So you could then call your repository like so:

MyRepository repository = new MyRepository();
var model = repository.Find<MyModel>(a=> a.Prop1 == 5);

If you want to not allow the user to put any kind of type int the generic argument you could have your models all inherit from a base class or impelement an interface and then change the find method to:

public  T Find<T>(Expression<Func<T,object>> expression) where T : IMyModelInterface //or whatever base class you want
Jose
Thank you Jose. I have not used LINQ before. My question would now be translated to if I use LINQ Expression as a parameter to Find function then how do I transform this expression to parameters that the Web Service method requires? Expression will certainly help for my in memory cache / data collection but my main question was about calling web service scenario.
byte
I think the easiest would be to have the webservice take in an expression tree as a parameter as well, implement an IQueryable within the web service (i.e. Linq To SQL) and then just feed it the expression within the web service and then you don't have to do any parsing, just passing the buck along. :)
Jose
Thanks. The problem is I can't modify the web service. It may also not be a .NET web service (could be Java or C++ on unix).So the WebMethod would be something like string FindMembers(string lastname, int minAge, string city)where the return type is XML as string
byte
Then I believe the best option would be to make the repository have the same exact methods as your web service, and then cache the results in your repository after each call
Jose
Thanks. Appreciate your replies.
byte