public class SomeController : Controller { const string EFIndicator = "System.Data.Entity.Internal.Linq.DbQueryProvider"; IQueryable<Question> _q = null; public SomeController (IQueryable<Question> q) { _q = q; } public ViewResult ShowEverything(int id) { Question q = null; var q1 = _q.Where(x => x.QuestionId == id); if (_q.Provider.ToString() == EFIndicator) { var backToEf = (System.Data.Entity.Infrastructure.DbQuery<Question>)q1; q = backToEf .Include("AskedBy") .Include("QuestionModifiedBy") .Include("QuestionComments") .Include("Answers") .Include("Answers.AnswerComments") .Single(); } return View(q); } }
And you have to anticipate different eager-loading mechanism based on the IQueryable ORM provider too, e.g. NHibernate:
public ViewResult ShowEverything(int id) { Question q = null; var q1 = _q.Where(x => x.QuestionId == id); if (_q.Provider.ToString() == EFIndicator) { var backToEf = (System.Data.Entity.Infrastructure.DbQuery<question>)q1; q = backToEf .Include("AskedBy") .Include("QuestionModifiedBy") .Include("QuestionComments") .Include("Answers") .Include("Answers.AnswerComments") .Single(); } else if (_q.Provider is NHibernate.Linq.DefaultQueryProvider) { q1 .FetchMany(x => x.QuestionComments) .ToFuture(); q1 .Fetch(x => x.AskedBy) .Fetch(x => x.QuestionModifiedBy) .FetchMany(x => x.Answers) .ToFuture(); //sess.Query<answer>() //.Where(x => x.Question.QuestionId == id) //.FetchMany(x => x.AnswerComments) //.ToFuture(); q = q1.ToFuture().Single(); } else { // Repository pattern is unit-testing friendly code ツ q = q1.ToSingle(); } return View(q); }
You'll notice in the code above that we cannot eager-load NHibernate's AnswerComments. So you have to pass the Answer repository too. An argument can be made that NHibernate can leak repository abstractions. Following is the repository pattern-using code that supports NHibernate eager-loading mechanism. Though if you have a good dependency injection component, you don't have to worry about changes, laugh in the face of changes when you use empowering tools.
public class SomeController : Controller { const string EFIndicator = "System.Data.Entity.Internal.Linq.DbQueryProvider"; IQueryable<Question> _q = null; IQueryable<Answer> _a = null; public SomeController (IQueryable<Question> q, IQueryable<Answer> a) { _q = q; _a = a; } public ViewResult ShowEverything(int id) { Question q = null; var q1 = _q.Where(x => x.QuestionId == id); if (_q.Provider.ToString() == EFIndicator) { var backToEf = (System.Data.Entity.Infrastructure.DbQuery<Question>)q1; q = backToEf .Include("AskedBy") .Include("QuestionModifiedBy") .Include("QuestionComments") .Include("Answers") .Include("Answers.AnswerComments") .Single(); } else if (_q.Provider is NHibernate.Linq.DefaultQueryProvider) { q1 .FetchMany(x => x.QuestionComments) .ToFuture(); q1 .Fetch(x => x.AskedBy) .Fetch(x => x.QuestionModifiedBy) .FetchMany(x => x.Answers) .ToFuture(); _a .Where(x => x.Question.QuestionId == id) .FetchMany(x => x.AnswerComments) .ToFuture(); q = q1.ToFuture().Single(); } else {} // Very unit-testing-friendly :-) q.QuestionText = q.QuestionText + "?"; return View(q); } }
Sample unit test:
// Arrange int id = 1; string qt = "Answer to life and everything"; var questions = new List<Question> { new Question{ QuestionId = id, QuestionText = qt } }.AsQueryable(); var answers = new List<Answers> { new Answer{ Question = questions[0], AnswerText = "4" } }.AsQueryable(); // Act Question q = (Question) new SomeController( questions, answers).ShowEverything(id); // Assert Assert.AreEqual(qt + "?", q.QuestionText);
Sample integration tests:
using (var db = new EfMapping()) { // Arrange int id = 1; IQueryable<Question> questions = db.Set<Question>(); IQueryable<Answer> answers = db.Set<Answer>(); Question qX = db.Set<Question>().Find(id); // Act Question q = (Question) new SomeController(questions, answers).ShowEverything(id); // Assert Assert.AreEqual(qX.QuestionText + "?", q.QuestionText); } /* for NHibernate: using (var sess = NhMapping.GetSessionFactory().OpenSession()) { // Arrange int id = 1; IQueryable<Question> questions = sess.Query<Question>(); IQueryable<Answer> answers = sess.Query<Answer>(); Question qX = sess.Query<Question>().Load(id); // Act Question q = (Question) new SomeController(questions, answers).ShowEverything(id); // Assert Assert.AreEqual(qX.QuestionText + "?", q.QuestionText); */
No comments:
Post a Comment