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