views:

74

answers:

4

I have the understanding that using data access routines directly from presentation code is considered evil. So I have a separate Repositories project, as well as a Services project. From what I can tell, typical use of a service layer is to insulate the data access from the presentation. All well and good.

I have a pretty simple domain, simply a Movie class. A matching repository interface is:

public interface IMovieRepository
{
    void AddMovie(Movie movie);
    void UpdateMovie(Movie movie);
    void RemoveMovie(Movie movie);
    int GetMovieCount();
    Movie GetMovieById(int id);
    IEnumerable<Movie> GetAllMovies();
    IEnumerable<Movie> GetMoviesByGenre(Genre genre);
    IEnumerable<Movie> GetMoviesByYear(int year);
    IEnumerable<Movie> GetMoviesByActor(string actor);
    IEnumerable<Movie> GetMoviesByTitle(string title);
}

Now when I get to a service class to use the repository, I wind up defining an interface like this:

public interface IMovieService
{
    Movie CreateMovie(string title, int year, Genre genre, int length, IEnumerable<string> actors);
    void UpdateMovie(Movie movie);
    void RemoveMovie(Movie movie);
    int GetMovieCount();
    Movie GetMovieById(int id);
    IEnumerable<Movie> GetAllMovies();
    IEnumerable<Movie> GetMoviesByGenre(Genre genre);
    IEnumerable<Movie> GetMoviesByYear(int year);
    IEnumerable<Movie> GetMoviesByActor(string actor);
    IEnumerable<Movie> GetMoviesByTitle(string title);
}

The two interfaces are very similar, which strikes me as odd. I expect that an IMovieService implementation would use an IMovieRepository implementation internally, essentially being a thin wrapper on the latter. There could probably be some validation or caching or the like, but the former seems like it would simply pass through to the latter in most cases.

Am I going about this the right way, or is there something I'm missing?

I know it seems a bit overkill for such a simple domain, but I'm trying to nail down the pattern of layering and abstraction for use in future - and larger - projects.

EDIT: to be a bit clearer, I'm not talking about NHibernate or the repository pattern, but rather about the layering of concerns.

UPDATE: thanks folks. I believe I will keep the specific query methods on the service class, to be straightforward for the UI layer, and try to generalize the repository some by passing queries to a query function.

A: 

Given the interface IMovieRepository as you have defined it the IMovieService interface is redundant. If the repository interface was generic as given below, then there is value to the service interface. I prefer the simpler repository interface because to me it provides a better separation of concerns

public interface IRepository<T> {
    IQueryable<T> Fetch();
    void Save(T item);
    void Remove(T item);
}
Eric Weilnau
A: 

Having a Service class simply to wrap a repository is IMO unneeded complexity.

I usually end up having bool Try... methods (TrySave, TryDelete etc.) in the Service-layer (if I have any) and then add error messages as out-parameters. I only let Repositories handle persistence concerns - getting it in and out of the repository.

As for querying - I don't let that through my Service unless, I have UI-centric complex filter objects that need to be 'translated' before they hit the Repository.

Hope this helps!

Goblin
A: 

I typically like to place more complex queries in my service classes. Ones that call some repository method and then use additional Linq to Object methods to produce the desired data set.

WSkinner
A: 

I think you're right on track. The reason why your DataAccess API and ServiceAPI look so similar is you haven't given your service any real business logic yet. Here's a few brainstorms of things that might end up on your service API, but would involve some more complex operations than simple CRUD (Create, Read, Update, Delete) functionality. Obviously these are just quick and dirty examples, but I'm sure you get the idea:

  • RecommendMovieToFriend(int movieID, string friendEmail);
  • RateMovie(int movieID, int numberOfStars);
  • AddMovieToMyWishList(int movieID, int userID);

I think the separation of ServiceLayer and DataLayer is an important and valuable one, and you shouldn't second-guess it, even though the two APIs are currently very similar. As the functionality of your service grows, the two APIs will continue to diverge, to meet the needs of their callers.

mikemanne