Quantcast
Channel: ASP.NET Core
Viewing all articles
Browse latest Browse all 9386

Problem with relationship between User (testTaker) and Question while writin LINQ in action

$
0
0

Hi guys,

I develop Quiz application where users can login and take test. My problem is that I cannot write right action in controller so that when each user submit their answer while they are logged in, and if it's true, the relevant question score for each user must be saved in database.  Each user holds testTakerId , and there is many-to-many relationship between TestTaker and Question object as all test takers will have many questions and each question will concern all test takers. So, considering this, my model is like this:

Question

 public class Question
    {
        public Question()
        {
            Answers = new HashSet<Answer>();
        }

        public int Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public Exam Exam { get; set; }
        public int ExamId { get; set; }
        public TimeSpan? Remainedtime { get; set; }
        public int Score { get; set; }
        public ICollection<Answer> Answers { get; set; }
        public ICollection<UserQuestion> UserQuestions { get; set; }

    }    

ExamUser

 public class ExamUser: IdentityUser
    {
        public TestTaker TestTaker { get; set; }
        public int? TestTakerId { get; set; }
    }

TestTaker

 public class TestTaker
    {
        public int Id { get; set; }
        [Required]
        public string Name { get; set; }
        public string Phone { get; set; }
        public string Education { get; set; }
        public string Job { get; set; }
        public DateTime Birth { get; set; }
        public ExamUser ExamUser { get; set; }
        public int Result { get; set; }
        public ICollection<UserQuestion> UserQuestions { get; set; }
    }

UserQuestion (moderate table for many-to-many relationship)

 public class UserQuestion
    {
        public int TestTakerId { get; set; }
        public TestTaker TestTaker { get; set; }
        public int QuestionId { get; set; }
        public Question Question { get; set; }
    }

The reason why I didn't connect ExamUser directly to questions is that its built in Id is string (it might cause problem while inserting to database).

in DbContext:

  public class IntellectDbContext:IdentityDbContext<ExamUser>
    {
        public IntellectDbContext(DbContextOptions<IntellectDbContext> dbContextOptions) : base(dbContextOptions)
        {

        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<UserQuestion>()
                .HasKey(a => new { a.TestTakerId, a.QuestionId });

            modelBuilder.Entity<UserQuestion>()
                .HasOne(a => a.TestTaker)
                .WithMany(b => b.UserQuestions)
                .HasForeignKey(a => a.TestTakerId);

            modelBuilder.Entity<UserQuestion>()
                .HasOne(a => a.Question)
                .WithMany(c => c.UserQuestions)
                .HasForeignKey(a => a.QuestionId);
        }

        public DbSet<Answer> Answers { get; set; }
        public DbSet<Question> Questions { get; set; }
        public DbSet<Exam> Exams { get; set; }
        public DbSet<ExamUser> ExamUsers { get; set; }
        public DbSet<UserQuestion> UserQuestions { get; set; }
        public DbSet<TestTaker> TestTakers { get; set; }
    }

Question View in Exam:

@model Intellect.Models.ViewModels.AdminViewModel
<div class="questioncontainer"> <form asp-action="Question" asp-controller="Home" asp-route-id="@Model.NextQuestion.Id" asp-route-count="@ViewBag.Equestions"><div class="row"><div class="col-lg-3"></div><div class="col-lg-6 col-sm-12"><table><tr><th>Timer</th></tr><tr><td><label asp-for="Question.Remainedtime" id="time"></label><input type="hidden" id="timehidden" asp-for="Question.Remainedtime" /></td></tr></table><div class="question">@Model.CurrentQuestion.Description </div></div><div class="col-lg-3"></div></div><div class="row"><div class="col-lg-3 col-sm-0"></div> @{ int n = 0; } @foreach (Answer item in Model.Answers) { if (n == 0 || n == 2) { @: <div class="col-lg-3 col-sm-12"> @: <div class="firstpart"> }<input asp-for="@item.Id" name="@item.Id" hidden /><input type="radio" asp-for="@item.Id" name="myanswer" value="@item.Id" />@item.Description<br> if (n == 1 || n == 3) { @:</div> @:</div> } n++; }<div class="col-lg-3"></div></div><div class="row"><div class="col-lg-6 col-sm-4"></div><div class="col-lg-3 col-sm-4"></div><div class="col-lg-3 col-sm-4"><div class="nextbtn"> @if (ViewBag.Equestions == 0) {<input type="submit" value="Finish" /> } else {<input type="submit" value="Next" /> }</div></div></div></form></div> @section Script{ <script> var start = Date.now(), diff, seconds; function startTimer(duration) { function timer() { // get the number of seconds that have elapsed since // startTimer() was called diff = duration - (((Date.now() - start) / 1000) | 0); // does the same job as parseInt truncates the float seconds = diff; seconds = seconds < 10 ? "0" + seconds : seconds;$("#time").text(seconds);$("#timehidden").val(seconds); if (diff <= 0) { // add one second so that the count down starts at the full duration start = Date.now() + 1000; } }; // we don't want to wait a full second before the timer starts timer(); setInterval(timer, 1000); } window.onload = function () { var minute = 60 * @Model.Question.Remainedtime; startTimer(fiveMinutes); $("#time").val("start"); };</script> }

And finally, Controller (the problem is here)

 public class HomeController : Controller
    {
        private readonly IntellectDbContext _intellectDbContext;
        private readonly UserManager<ExamUser> _userManager;
        private readonly SignInManager<ExamUser> _signInManager;
        static int exam_id = 0;
        static int? PreviousId = 0;
        static int result = 0;
        static int correctAnswer = 0;
        static List<Question> RemainedQuestions = new List<Question>();
        static List<int> trueAnswers = new List<int>();

        public HomeController(IntellectDbContext intellectDbContext, UserManager<ExamUser> userManager, SignInManager<ExamUser> signInManager)
        {
            _intellectDbContext = intellectDbContext;
            _userManager = userManager;
            _signInManager = signInManager;
        }
        public IActionResult Index()
        {
            return View();
        }

        public IActionResult About()
        {
            return View();
        }

        public IActionResult Contact()
        {
            ViewData["Message"] = "Your contact page.";

            return View();
        }

        public IActionResult Privacy()
        {
            return View();
        }

        [HttpGet]
        public async Task<IActionResult> Test(int Id)
        {
            exam_id = Id;
            AdminViewModel admodel = new AdminViewModel();
            admodel.Equestions = await _intellectDbContext.Questions.Include(q => q.Answers).Where(q => q.ExamId == Id).ToListAsync();
            admodel.CurrentQuestion = await _intellectDbContext.Questions.Where(q => q.ExamId == Id).FirstOrDefaultAsync();
            RemainedQuestions = admodel.Equestions;
            PreviousId = admodel.CurrentQuestion.Id;
            return View(admodel);
        }

        public async Task<IActionResult> Question(int Id, int count, int myanswer)
        {
            AdminViewModel admodel = new AdminViewModel();
            admodel.CurrentQuestion = await _intellectDbContext.Questions.Where(x => x.Id == Id).SingleOrDefaultAsync();
            admodel.Answers = await _intellectDbContext.Answers.Where(y => y.QuestionId == Id).ToListAsync();
            admodel.Equestions = await _intellectDbContext.Questions.Where(q => q.ExamId == exam_id).ToListAsync();
            admodel.CurrentQuestion.Remainedtime = new TimeSpan(0, 0, 60);

            correctAnswer = _intellectDbContext.Answers.Where(a => a.QuestionId == PreviousId && a.Correct == true).SingleOrDefault().Id;

            if(myanswer == correctAnswer)
            {
                result = int.Parse(admodel.Question.Remainedtime.ToString());
                // admodel.CurrentQuestion.Score = result;
            }

            if (_signInManager.IsSignedIn(User))
            {
                ExamUser examTaker = await _userManager.GetUserAsync(HttpContext.User);
                examTaker.TestTaker = await _intellectDbContext.TestTakers.FirstOrDefaultAsync();
                examTaker.TestTaker.UserQuestions = await _intellectDbContext.UserQuestions.ToListAsync();
                admodel.CurrentQuestion = examTaker.TestTaker.UserQuestions.Select(u => u.Question).Where(x => x.Id == Id).SingleOrDefault();admodel.CurrentQuestion.Score = result;
            }

                if (count > 1)
            {
                var question = RemainedQuestions.Single(r => r.Id == admodel.CurrentQuestion.Id);
                PreviousId = question.Id;
                RemainedQuestions.Remove(question);
                admodel.NextQuestion = RemainedQuestions[0];
                count -= 1;
            }
            else
            {
                admodel.NextQuestion = RemainedQuestions[0];
                count -= 1;
            }

            if(count == -1)
            {
                return RedirectToAction(nameof(Finish));
            }

            ViewBag.Equestions = count;

            return View(admodel);
        }
        
       
        }

Please, mainly focus on Question action as this action will do the main job. Result is calculated according to remianed time which will be the question's point. First, while running application, the code I highlighted (admodel.CurrentQuestion.Score = result;) gives null reference exception though I defined it in the code line before it. As moderate table (UserQuestion) shows only Ids in its table in SQLServer, I cannot see actually where each user's question score might be inserted. Only if joining these 3 tables, maybe we can see result if action is done successfully. How can I solve it? Has anyone faced such experience? 

Hope, one of you can find solution to this problem. Thanks in advance!


Viewing all articles
Browse latest Browse all 9386

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>