FCin FCin -3 years ago 137
ASP.NET (C#) Question

Join DbSets with repository pattern

I have basic implementation of repository pattern with generic

IRepository<T>
which holds
Add
,
Remove
,
Find
, etc. and I have more precise repositories such as
IActorRepository
and
IFilmRepository
that derive from
IRepository
. I have a method for search box that finds top 5 actors and films that match text from the search box.

My question is how can I join these to repositories? I need my method to be testable, so I don't want
IQueryable
in my method, just an interface I can mock later on.

The only thing for me that comes to mind is to create some kind of helper class such as
public class FilmsActorsHelper: IFilmsActorsHelper
. I'm sure someone had an issue like that, what is a common practice here, how is it usually solved?

Method for which I need a solution:

[HttpPost]
public ActionResult SearchBoxChanged(string inputValue) {
if (inputValue == null || inputValue.Length < 3)
return Json(new List<string>());

const int maxNamesCount = 5;
var names = _filmRepository.Find(f => f.Name.Contains(inputValue)).Select(f => f.Name).Take(maxNamesCount).ToList();
var remaining = maxNamesCount - names.Count;
var actorNames = _actorRepository.Find(f => f.Name.Contains(inputValue)).Select(f => f.Name).Take(remaining).ToList();
names.AddRange(actorNames);

return Json(names);
}


Also, because I have
ToList()
I suspect it will pull everything from database, right?

Answer Source

Do not wrap a type that already implements a Repository pattern (DbContext) in your own Repository type(s). You are adding an unneeded abstraction that only makes your code more difficult to read and you have to jump through hoops to do simple things like joining tables. Create a service instead that has an instance of your DbContext and do your work in there and return a result. Consume that service from your Controller. Then you can join on whatever you want.

Services should encapsulate and expose business logic. So if you want to return a list of films based on actor then you would have some method like Task<List<Film>> GetFilmsForActorAsync(string actor) that would do that. Do not try to wrap each entity in its own service, then you have added nothing of real value.

You can also split your services based on functionality and read/write. See CQRS pattern.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download