System.InvalidOperationException: There is no method 'FetchMany' on type 'NHibernate.Linq.EagerFetchingExtensionMethods' that matches the specified arguments
Don't do this:
public MovieController : Controller { IRepository<Movie> _db; public MovieController(IRepository<Movie> db) { _db = db; } public ViewResult ShowMovieInfo(int id) { var query = (from x in _db.All where x.MovieId == id select x).FetchMany(x => x.Quotes); var movie = query.Single(); return View(movie); } }
When you perform unit testing on your controller, it will fail on FetchMany; NHibernate will throw an exception when the IQueryable(the All property of _db repository) didn't came from NHibernate, e.g. mocked IQueryable.
To make your controller unit testing-friendly, isolate and conditionally suppress anything that are not a factor on program correctness. NHibernate's FetchMany is one of those, even without FetchMany you can verify the program correctness. FetchMany is for performance optimization only.
Do this instead:
public MovieController : Controller { IRepository<Movie> _db; public MovieController(IRepository<Movie> db) { _db = db; } public ViewResult ShowMovieInfo(int id) { var query = from x in _db.All where x.MovieId == id select x; if (query.Provider.GetType() == typeof(NHibernate.Linq.NhQueryProvider)) query = query.FetchMany(x => x.Quotes); var movie = query.Single(); return View(movie); } }
Note: On NHibernate 3.2, there's no more NhQueryProvider, it's replaced with DefaultQueryProvider
Thanks, that helped a lot :)
ReplyDeleteThanks, glad I found this!
ReplyDeleteI took the long way around instead; built my own set of these Fetch extension methods, and a wrapper for the INhFetchRequest, that wrapped NHibernate's own. It had the added advantage, when I first built it, of preventing consuming code from having to directly reference NH instead of my encapsulated Repository interface/classes. "No problem you can't solve with another layer of abstraction, except for having too many".
ReplyDeleteInformation here is valid. Great post.
ReplyDelete