Click here to Skip to main content
15,039,359 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I am trying to create a Job record using EF Core and then displaying after hitting the create button I want to display a table list of unassignedUsers that don't contain matching ID of the newly created record. 

But I cannot even display the page and will be shown the error page instead. This occurs in the 'var id=@model.ID' for the unassignedUsersTable which I am instantiating in DataTables. Because I haven't created a Job object with ID so ASP.NET MVC 5 cannot check database to see if there are any users with matching job id. This is where I'm stuck. I do not know how to delay ASP.NET from checking for if newly created record ID exists after user hits the submit button.

Here is the code I'm stuck on:

Models/Users.cs


C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Pitcher.Models;
namespace Pitcher.Models
{
    public class User
    {      
        public int ID { get; set; }

        [Required]
        [StringLength(20, MinimumLength = 2, ErrorMessage = "* First Name be bettween 2 to 20 characters.")]
        [DataType(DataType.Text)]
        [Display(Name = "First Name")]
        [Column("UserFirstName")]
        public string UserFirstName { get; set; }   

        [Required]
        [StringLength(30, MinimumLength = 2, ErrorMessage = "* Last Name be bettween 2 to 30 characters.")]
        [DataType(DataType.Text)]
        [Display(Name = "Last Name")]
        [Column("UserLastName")]
        public string UserLastName { get; set; }        
                
        [Required]
        [StringLength(30, MinimumLength = 3, ErrorMessage = "Email address must be bettween 3 to 30 characters.")]
        [DataType(DataType.EmailAddress)]
        [Display(Name = "Email")]
        [Column("UserContactEmail")]
        public string UserContactEmail{get;set;}      
        
        // [Required(AllowEmptyStrings = true)]
        [Display(Name = "Phone Number")]
        [Phone()]
        [Column("UserPhoneNumber")]
        public string UserPhoneNumber{get;set;}
        
        [StringLength(37,ErrorMessage = "Address cannot be longer than 37 characters.")]
        [DataType(DataType.Text)]
        [Display(Name = "Address")]
        [Column("UserAddress")]
        public string UserAddress{get;set;}
        
        //This regular expression allows valid postcodes and not just USA Zip codes.        
        [Display(Name = "Post Code")]
        [Column("UserPostCode")][DataType(DataType.PostalCode)]
        public string UserPostCode { get; set; }

        [StringLength(15,ErrorMessage = "Country cannot be longer than 15 characters.")]
        [DataType(DataType.Text)]
        [Display(Name = "Country")]
        [Column("UserCountry")] 
        public string UserCountry {get;set;}
        
        
        [Phone()]
        [Display(Name = "Mobile Number")]
        [Column("UserMobileNumber")]
        public string UserMobileNumber {get;set;}

        [StringLength(3,ErrorMessage = "State cannot be longer than 3 characters.")]
        [DataType(DataType.Text)]
        [Display(Name = "State")]
        [Column("UserState")]
        public string UserState {get;set;}           
        
        public string UserFullname => string.Format("{0} {1}", UserFirstName, UserLastName);

        public ICollection Registrations {get;set;}
    }
}



Models/Jobs.cs


C#
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;

namespace Pitcher.Models
{
    public class Job
    {        
        
        public int ID { get; set; }

        [Required]
        [StringLength(20, MinimumLength = 3, ErrorMessage = "Job Title must be bettween 3 to 20 characters.")]
        [DataType(DataType.Text)]
        [Display(Name = "Job Title")]
        [Column("JobTitle")]
        public string JobTitle { get; set; }

        [StringLength(200, MinimumLength = 3, ErrorMessage = "Job Description must be bettween 200 to 3 characters.")]
        [DataType(DataType.Text)]
        [Display(Name = "Description")]
        [Column("JobDescription")]
        public string JobDescription { get; set; }

        [Required]
        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        [Display(Name = " Start Date")]
        [Column("JobStartDate")]
        public DateTime JobStartDate {get;set;}

        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        [Display(Name = "Deadline Date")]
        [Column("JobDeadlineDate")]
        public DateTime JobDeadline {get;set;}

        [Display(Name = "Job Is Complete?")]
        [Column("JobIsComplete")]
        public bool JobIsComplete{get;set;}

        public ICollection Registrations {get;set;}

        public ICollection Results {get;set;}
    }   
}


Views/Jobs/Create.cshtml


ASP.NET
<pre>@model Pitcher.Models.Job
@{ 
    var user = new User();
}
@{
    ViewData["Title"] = "Create";
}

<h1>Create</h1>

<h4>Job</h4>
<hr />
<div class="row">
    <div class="col-md-4">        
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="JobTitle" class="control-label"></label>
                <input asp-for="JobTitle" class="form-control" />
                <span asp-validation-for="JobTitle" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="JobDescription" class="control-label"></label>
                <textarea asp-for="JobDescription" class="form-control" rows="10" cols="50"></textarea>
                <span asp-validation-for="JobDescription" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="JobStartDate" class="control-label"></label>
                <input asp-for="JobStartDate" class="form-control" />
                <span asp-validation-for="JobStartDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="JobDeadline" class="control-label"></label>
                <input asp-for="JobDeadline" class="form-control" />
                <span asp-validation-for="JobDeadline" class="text-danger"></span>
            </div>
            <div class="form-group form-check">
                <label class="form-check-label">
                    <input class="form-check-input" asp-for="JobIsComplete" /> @Html.DisplayNameFor(model => model.JobIsComplete)
                </label>
            </div>
            <div class="form-group">
                <input type="submit" 
                value="Create" class="btn btn-primary" onclick='buttonClick()'/>
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-action="Index">Back to List</a>
</div>

@* <table id="registeredUsersTable" class="table" style="display: none">
<thead>
        <tr>
            <th>
               @Html.DisplayNameFor(model => user.UserFirstName)
            </th>        
            <th>
               @Html.DisplayNameFor(model => user.UserLastName)
            </th>
            <th>
               @Html.DisplayNameFor(model => user.UserContactEmail)
            </th>
            <th>                
            </th>
        </tr>
    </thead>
    <tbody></tbody>
</table> *@

@* Hide table before submission of record to DB *@
<table id="unassignedUsersTable" style='display:none;'>
<thead>
        <tr>
            <th>
               @Html.DisplayNameFor(model => user.UserFirstName)
            </th>        
            <th>
               @Html.DisplayNameFor(model => user.UserLastName)
            </th>
            <th>
               @Html.DisplayNameFor(model => user.UserContactEmail)
            </th>
            <th>                
            </th>
        </tr>
    </thead>
    <tbody></tbody>
</table>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
    <script>
    $.fn.dataTable.ext.errMode = 'throw';
    @* function buttonClick(){
    document.getElementById('registeredUsersTable').style.display = 'block';
        var id=@Model.ID  = $('#registeredUsersTable').DataTable({
            "ajax": {
            'type': 'get',
            //PROBLEM:Cannot get the related UserID of the Job.
            'data': { ID: id},
            'dataType': "json",                  
            "url": "@Url.Action("GetAllUsersByJobId")",
            "dataSrc": function (result) {
                return result;
                }
            },            
            "columns": [                
            { "data": "userFirstName"},
            { "data": "userLastName"},
            { "data": "userContactEmail"}
            ]
        });
    }         *@        

    //Reveal table if button click successful.  
    function buttonClick(){  
        document.getElementById('unassignedUsersTable').style.display = 'block'; 
        var id=@Model.ID
        $('#unassignedUsersTable').DataTable({
                "ajax": {
                type: 'get',
                'dataType': "json",
                //Get users from UsersController.                  
                "url": "@Url.Action("GetUnassignedUsersJobId")",
                "dataSrc": function (result) {
                    return result;
                    }
                },            
            "columns": [                
                { "data": "userFirstName"},
                { "data": "userLastName"},
                { "data": "userContactEmail"},
                {
                    "data": null,
                    "render": function (value) {
                        return '<a href="/Users/Details/' + value.id + '"button type="button" class="btn btn-primary btn-block">Details</a> <br> '
                            
                            + '<a href="/Users/Edit/' + value.id + '"button type="button" class="btn btn-info btn-block">Edit </a> <br> ' 
                            
                            + '<a href="/Users/Delete/' + value.id + '"button type="button" class="btn btn-primary btn-block">Delete</a>';
                    }
                }
                ]
        })
    };
        
    </script>
}


JobsController.cs


C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using Pitcher.Data;
using Pitcher.Models;
using Pitcher.Models.TeamViewModels;


namespace Pitcher.Controllers
{
    public class JobsController : Controller
    {
        private readonly TeamContext _context;


        public JobsController(TeamContext context)
        {
            _context = context;
        }

        // GET: Jobs/Create
        public IActionResult Create()
        {
            return View();
        }

        public IActionResult GetUnassignedUsersJobId(int? ID)
        {
            if (ID == null)
            {
                return NotFound();
            } 
            //Get most recently created Job ID.
            _context.Jobs.OrderByDescending(j => j.ID).FirstOrDefault();
            var userlist = _context.Registrations.Where(r => r.JobID != ID).Select(r => r.User).ToList();
            return Json(userlist);
        }     

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create([Bind("JobTitle,JobDescription,JobStartDate,JobDeadline,JobIsComplete")] Job job)
        {
            try
            {
                if (ModelState.IsValid)
                {                    
                    _context.Add(job);
                    await _context.SaveChangesAsync();
                    // return RedirectToAction(nameof(Index));
                }
                    ViewData["Jobs"] = _context.Jobs.ToList();
            }
            catch(DbUpdateException /* ex */)
            {
                //Log the error (uncomment ex variable name and write a log).
                ModelState.AddModelError("", "Unable to save changes. " +
                "Try again, and if the problem persists " +
                "See your system administrator.");
            }
            return View(job);
        }
    }
}

TeamContext.cs


C#
using Pitcher.Models;
using Microsoft.EntityFrameworkCore;
using Pitcher.Models.TeamViewModels;

namespace Pitcher.Data
{
    public class TeamContext : DbContext
    {
        public TeamContext(DbContextOptions<TeamContext> options) : base(options)
        {
        }

        public DbSet<User> Users { get; set; }
        public DbSet<Registration> Registrations {get;set;}
        public DbSet<Job> Jobs {get;set;}     

        public DbSet<Problem> Problems { get; set; }   

        public DbSet<Result> Results {get;set;}
        
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<User>().ToTable("tblUser");
            modelBuilder.Entity<Registration>().ToTable("tblRegistration");
            modelBuilder.Entity<Job>().ToTable("tblJob");
            modelBuilder.Entity<Problem>().ToTable("tblProblem");
            modelBuilder.Entity<Chat>().ToTable("tblChat");
            modelBuilder.Entity<Result>().ToTable("tblResult");
        }        
    }
}


What I have tried:

I'll elaborate further. My objective (if you or someone else can help me please) is to delay that null object from being instantiated until I...

1. Click 'submit'. 
2. ASP generates an ID for the record (which it is successfully doing).
3. ASP Saves record to database (which it is successfully doing).
4. ASP then gets the most newly created record by ID. I don't know how to do that.
5. That ID will be stationed in memory so we can render it to the unassignedUsersTable.
6. The object 'var id=@model.ID' then gets instantiated in memory instead of returning null.
Posted
Updated 4-Feb-21 0:42am

1 solution

Your Create action calls View with no parameters. Therefore, your Model will be null, and attempting to access @Model.Id will throw a NullReferenceException.

Change your action to pass in a new empty instance of the model instead:
C#
// GET: Jobs/Create
public IActionResult Create()
{
    var job = new Job();
    return View(job);
}
   
Comments
Jordan Nash 6-Feb-21 19:58pm
   
Thanks for your help Richard. While your answer solves the initial problem I listed in the title, it doesn't display a table list of unassigned users that don't contain matching ID of the newly created record. I'm wondering if you would know how to do that please? I'm stuck right now.

To elaborate, In the method JobsController.GetUnassignedUsersJobId(int? ID) I have ascertained that we are getting the last JobID but we are not comparing it to all the records in the userlist.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900