如何使用EF Core 3.1.5解决ASP.net Core应用程序中的空引用异常



当我将以下内容添加到"客户端详细信息"视图时,我得到了一个空引用异常:

<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>

为什么我在@Html.DisplayNameFor(model => model.Contacts)处得到一个空引用异常,以及如何修复它?

以下是删除了数据注释以便于阅读的Client类:

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; }
}
}

以下是Contact类,也删除了数据注释以便于阅读:

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; }
}
}

当我删除引用时,应该获得联系信息的代码,详细信息页面就可以工作了。当我将此代码添加到视图中时,它就会失败。以下是客户详细信息视图:

@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>

以下是控制器代码:

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);
}

您应该在客户端模型构造函数中初始化Contacts集合,如下

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; }
}

}

应该是这样的,将Id更改为ClientID,并在需要主键和制作表的地方制作[Key][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; }
}

Id更改为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; }
}

您的控制器应该声明一个列表,并将视图模型发送到剃刀页面。应该看起来像这样:

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);
}

您应该对将要创建数据库的所有模型执行相同的操作。在您的联系人页面中,您没有提到您正在使用哪个@model,但它应该是这样的:@model List<YourProject.UI.Models.Contacts>

相关内容

最新更新