Reputation: 105
New to C# and MVC, so probably an obvious error: My Controller logic does not send any db items to the View. I don't know what I'm doing wrong.
I am building a multiple choice online test and have two db entitiy classes
public partial class Answer
{
public int ID { get; set; }
public string CorrectAnswer { get; set; }
public string Foil1 { get; set; }
public string Foil2 { get; set; }
public string Foil3 { get; set; }
}
public partial class Question
{
public int ID { get; set; }
public string Text { get; set; }
public string Level { get; set; }
public string GrammarPoint { get; set; }
}
I want to display questions and answer options in a View so I have this ViewModel
public class ExamViewModel
{
public string CorrectAnswer { get; set; }
public string Foil1 { get; set; }
public string Foil2 { get; set; }
public string Foil3 { get; set; }
public string Text { get; set; }
}
This is the Controller.
public ActionResult TakeTest()
{
ActiveTestEntities db = new ActiveTestEntities();
ExamViewModel exam = new ExamViewModel();
exam.Text = db.Questions.FirstOrDefault(t => t.ID == 1).ToString();
exam.Foil1 = db.Answers.FirstOrDefault(t => t.ID == 1).ToString();
exam.Foil2 = db.Answers.FirstOrDefault(t => t.ID == 1).ToString();
exam.Foil3 = db.Answers.FirstOrDefault(t => t.ID == 1).ToString();
exam.CorrectAnswer = db.Answers.FirstOrDefault(t => t.ID == 1).ToString();
return View(exam);
}
The LINQ is supposed to send db items to this View:
@model AccessEsol.Models.ExamViewModel
@{
ViewBag.Title = "TakeTest";
}
<h2>TakeTest</h2>
@using (Html.BeginForm()) {
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<fieldset>
<div class="display-label">
<h3>Click the correct answer:</h3>
</div>
<div class="display-field">
@Html.DisplayFor(model => model.Text )
</div>
<input id="Checkbox1" type="checkbox" />
@Html.DisplayFor(model => model.Foil1)
<input id="Checkbox1" type="checkbox" />
@Html.DisplayFor(model => model.Foil2)
<input id="Checkbox1" type="checkbox" />
@Html.DisplayFor(model => model.CorrectAnswer )
<input id="Checkbox1" type="checkbox" />
@Html.DisplayFor(model => model.Foil3)
<p>
<input type="submit" value="Submit Answers" />
</p>
</fieldset>
}
But beside each Checkbox displays AccessEsol.Models.Answer only, the db items have not been retrieved.
Much appreciated if you can tell me what I am doing wrong.
Upvotes: 0
Views: 1326
Reputation: 6423
since you have a question and view class defined I would use them in your view model instead of redefining the fields
public class ExamViewModel
{
public Answer Answer{ get; set; }
public Question Question { get; set; }
}
then on your view you will use it as
@Html.DisplayFor(x => x.Answer.Foil1)
On your controller you define the object but I don't see where you are calling the database. put a break point on your controller and make sure you database object has the data you are wanting to send to the view
Upvotes: 1
Reputation: 13381
you use linq wrong
db.Answers.FirstOrDefault(t => t.ID == 1)
this return object Answer
but you need for example Answer.Foil1
so try change your code like this
ExamViewModel exam = (from q in db.Questions
from a in db.Answers
where q.ID == 1 && a.ID==1
select new ExamViewModel{
Foil1 = a.Foil1,
Foil2 = a.Foil2,
Foil3 = a.Foil3,
CoorectAnswer = a.CorrectAnswer,
Text = q.Text
}).FirstOrDefault()
Upvotes: 1
Reputation: 218808
When you call .ToString()
on an object, the output is the type name of that object. That's why you're seeing:
AccessEsol.Models.Answer
That is the result of calling .ToString()
on any object of type AccessEsol.Models.Answer
.
What are those objects? Instead of trying to convert them to strings, use the objects themselves. So your view model would be more like this:
public class ExamViewModel
{
public Answer CorrectAnswer { get; set; }
public Answer Foil1 { get; set; }
public Answer Foil2 { get; set; }
public Answer Foil3 { get; set; }
public Question Text { get; set; }
}
And then you'd just remove the calls to .ToString()
in your controller:
exam.Text = db.Questions.FirstOrDefault(t => t.ID == 1);
exam.Foil1 = db.Answers.FirstOrDefault(t => t.ID == 1);
exam.Foil2 = db.Answers.FirstOrDefault(t => t.ID == 1);
exam.Foil3 = db.Answers.FirstOrDefault(t => t.ID == 1);
exam.CorrectAnswer = db.Answers.FirstOrDefault(t => t.ID == 1);
Then in your view, you'd access the actual properties on those objects. I don't know what those properties are called, so this is a guess, but it might be something like:
@Html.DisplayFor(model => model.Text.QuestionText)
This assumes that there's a property called QuestionText
on the Question
object which holds its text. Whatever that property is actually called in your code, just use that.
You could make your existing code work by overriding .ToString()
on your Question
and Answer
objects to output the desired strings. But that's not really a common approach and would needlessly complicate the code. The best approach is to just use the models you have, and keep them as their actual model types instead of trying to convert them to strings.
This isn't even necessarily an MVC issue, this is just plain C# code. Prefer strongly-typed objects over serialized strings.
Upvotes: 0