Reputation: 389
I'm getting a null reference exception when I add the following to the Client Details view:
<dt>
@Html.DisplayNameFor(model => model.Contacts)
</dt>
<dd>
<table class="table">
<tr>
<th>FN</th>
<th>LN</th>
<th>Email</th>
<th>Contact Type</th>
</tr>
@foreach (var item in Model.Contacts)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.FN)
</td>
<td>
@Html.DisplayFor(modelItem => item.LN)
</td>
<td>
@Html.DisplayFor(modelItem => item.Email)
</td>
<td>
@Html.DisplayFor(modelItem => item.ContactType)
</td>
</tr>
}
</table>
</dd>
Why am I getting a null reference exception at @Html.DisplayNameFor(model => model.Contacts)
and how can I fix it?
The following is the Client
class with the data annotations removed to make it easier to read:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace scms_core.Models
{
public class Client
{
public int Id { get; set; }
public string CrtdBy { get; set; }
public DateTime CrtdDt { get; set; }
public string FN { get; set; }
public string LN { get; set; }
public string BN { get; set; }
public int ClientTypeId { get; set; }
public tlClientType ClientType { get; set; }
public virtual ICollection<Contact> Contacts { get; set; }
}
}
The following is the Contact
class, also with the data annotations removed to make it easier to read:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace scms_core.Models
{
public class Contact
{
public int Id { get; set; }
public string CrtdBy { get; set; }
public DateTime CrtdDt { get; set; }
public string FN { get; set; }
public string LN { get; set; }
public string Email { get; set; }
public int ContactTypeId { get; set; }
public tlContactType ContactType { get; set; }
public int ClientId { get; set; }
public virtual Client Client { get; set; }
}
}
When I remove the reference the code that is supposed to get the Contact information, the details page works. It just fails when I add this code to the view. Below is the Client Details View:
@model scms_core.Models.Client
@{
ViewData["Title"] = "Details";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Details</h1>
<div>
<h4>Client</h4>
<hr />
<dl class="row">
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.CrtdBy)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.CrtdBy)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.CrtdDt)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.CrtdDt)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.FN)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.FN)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.LN)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.LN)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.BN)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.BN)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.ClientType)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.ClientType.ClientType)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Contacts)
</dt>
<dd>
<table class="table">
<tr>
<th>FN</th>
<th>LN</th>
<th>Email</th>
<th>Contact Type</th>
</tr>
@foreach (var item in Model.Contacts)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.FN)
</td>
<td>
@Html.DisplayFor(modelItem => item.LN)
</td>
<td>
@Html.DisplayFor(modelItem => item.Email)
</td>
<td>
@Html.DisplayFor(modelItem => item.ContactType)
</td>
</tr>
}
</table>
</dd>
</dl>
</div>
<div>
<a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
<a asp-action="Index">Back to List</a>
</div>
Below is the controller code:
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var client = await _context.Clients
.Include(c => c.ClientType)
.FirstOrDefaultAsync(m => m.Id == id);
if (client == null)
{
return NotFound();
}
return View(client);
}
Upvotes: 0
Views: 432
Reputation: 412
Should be like this, change Id
to ClientID
and make a [Key]
and [Table]
where you want to have primary key and making a table:
[Table("Client")]
public class Client
{
[Key]
public int ClientID { get; set; }
public string CrtdBy { get; set; }
public DateTime CrtdDt { get; set; }
public string FN { get; set; }
public string LN { get; set; }
public string BN { get; set; }
public int ClientTypeID { get; set; }
[ForeignKey("ClientTypeID")]
public ClientType ClientType { get; set; }
public int ContactID { get; set; }
[ForeignKey("ContactID")]
public virtual Contact Contact { get; set; }
public ICollection<Contact> Contacts { get; set; }
}
Change Id
to ContactID
[Table("Contact")]
public class Contact
{
[Key]
public int ContactID { get; set; }
public string CrtdBy { get; set; }
public DateTime CrtdDt { get; set; }
public string FN { get; set; }
public string LN { get; set; }
public string Email { get; set; }
public int ContactTypeID { get; set; }
[ForeignKey("ContactTypeID")]
public virtual ContactType ContactType { get; set; }
public int ClientID { get; set; }
[ForeignKey("ClientID")]
public virtual Client Client { get; set; }
}
Your controller should declare a list and send the view model to razor page. Should look something like this:
public async Task<ActionResult> Contacts()
{
var allClients = await _context.Clients.ToList();
List<Contact> viewModel = allClients.Select(x => new Contacts
{
FN = x.FN,
LN = x.LN,
Email = x.Email,
ContactType = x.ContactType
}).ToList();
return View(viewModel);
}
You should do the same for all models that are going to create the database. In your Contacts page, you did not mention which @model
you are using, but it should look something like this: @model List<YourProject.UI.Models.Contacts>
Upvotes: 0
Reputation: 511
you should initialize Contacts collection in the Client model constructor like this
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace scms_core.Models
{
public class Client
{
public Client()
{
Contacts = new HashSet<Contact>();
}
public int Id { get; set; }
public string CrtdBy { get; set; }
public DateTime CrtdDt { get; set; }
public string FN { get; set; }
public string LN { get; set; }
public string BN { get; set; }
public int ClientTypeId { get; set; }
public tlClientType ClientType { get; set; }
public virtual ICollection<Contact> Contacts { get; set; }
}
}
Upvotes: 1