【发布时间】:2021-07-21 05:11:00
【问题描述】:
我正在使用 ASP.NET Core (MVC) 创建一个 Web 应用程序。数据库是 SQL Server。代码优先设计。我是 EF 的新手。
我已经定义了Visitor 模型、Checkin 和 Checkout 模型,其中访客/签入的关系为 1:1,访客/结账的关系为 1:1。该应用程序的理念是在创建新访客时创建新的签到和新签出记录以及访客记录的子项。
我的模型如下(我使用ForeignKey数据注解来定义visitor和checkin以及visitor和checkout之间的一一对应关系):
public class Visitor
{
[Key]
public int Id { get; set; }
[DisplayName("Visitor First Name")]
[Required]
public string FirstName { get; set; }
[DisplayName("Visitor Last Name")]
[Required]
public string LastName { get; set; }
public CheckIn CheckIn { get; set; }
public CheckOut CheckOut { get; set; }
}
public class CheckIn
{
[ForeignKey("Visitor")]
public int Id { get; set; }
[DisplayName("Time In")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:g}")]
public DateTime Time { get; set; }
public Visitor Visitor { get; set; }
}
public class CheckOut
{
[ForeignKey("Visitor")]
public int Id { get; set; }
[DisplayName("Time Out")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:g}")]
public DateTime? Time { get; set; }
public Visitor Visitor { get; set; }
}
我的控制器中有一个 POST 方法,它应该在数据库中添加一个新的访问者以及一个新的签入和签出记录作为访问者记录的子项。
但是,我遇到了未将签入记录添加到数据库的问题:而是更新了数据库中的现有签入记录,因此其主键是新访问者记录的键 (ID)。新访客记录创建成功。此外,新的结帐记录也被正确创建并作为新访客记录的子项。这是来自我的控制器的 POST 方法的代码(删除了一些与此问题无关的代码)(也使用视图模型将数据从视图传递到控制器):
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ConfirmSignin(SignVM obj)
{
if (ModelState.IsValid)
{
var visitor = new Visitor();
var checkin = new CheckIn();
var checkout = new CheckOut();
checkin = obj.CheckIn;
checkout = obj.CheckOut;
visitor = obj.Visitor;
visitor.CheckIn = checkin;
visitor.CheckOut = checkout;
_context.Add(visitor);
_context.Add(checkin);
_context.Add(checkout);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index),"Home",new { LocationId = obj.Visitor.LocationId });
}
return View(obj);
}
访问者在数据库中创建成功:
结帐也在数据库中成功创建:
您会注意到结帐记录的 ID 与父记录访问者的 ID 匹配 - 所以这部分似乎工作正常。
但在数据库中添加新访客时,不会添加签到记录:
当我添加访客 ID=6 时,数据库中应该已经添加了一条新的签到记录 - 相反,EF 更新了现有的签到记录并将其主键从 5(上一个访客)更新为 6(新访客)。
我假设我在控制器代码中做错了什么。有什么建议吗?
更新 - 2021 年 4 月 28 日: 下面是对应GET方法的代码:
[HttpGet]
public IActionResult ConfirmSignin()
{
SignVM signVM = new();
if (TempData["NewSignIn"] is string s)
{
signVM = JsonConvert.DeserializeObject<SignVM>(s);
}
ViewData["LocationName"] = new SelectList(_context.Locations, "Id", "Name", signVM.Visitor.LocationId);
return View(signVM);
}
下面是更新后的POST方法完整代码:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ConfirmSignin(SignVM obj)
{
if (ModelState.IsValid)
{
var escort = new Escort();
escort = await _context.Escorts
.Include(c => c.CheckIn)
.FirstOrDefaultAsync(m => m.EmployeeId == obj.Escort.EmployeeId);
if (escort == null)
{
escort = obj.Escort;
_context.Add(escort);
await _context.SaveChangesAsync();
}
var visitor = obj.Visitor;
var checkin = obj.CheckIn;
var checkout = obj.CheckOut;
visitor.CheckIn = checkin;
visitor.CheckOut = checkout;
escort.CheckIn = new List<CheckIn>();
escort.CheckOut = new List<CheckOut>();
escort.CheckIn.Add(checkin);
escort.CheckOut.Add(checkout);
_context.Add(visitor);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index),"Home",new { LocationId = obj.Visitor.LocationId });
}
return View(obj);
}
这是对应视图的代码:
@model VisitorLog.Models.ViewModels.SignVM
@{
ViewData["Title"] = "Sign In";
}
<div class="row justify-content-center mt-3">
<div class="col-md-4">
<div class="h4 text-center">Confirm Sign In</div>
<hr />
<form asp-action="ConfirmSignin">
<div class="form-group">
<label asp-for="Visitor.LocationId" class="control-label"></label>
<select asp-for="Visitor.LocationId" class="form-control" disabled asp-items="ViewBag.LocationName"></select>
</div>
<div class="form-group">
<label asp-for="Visitor.FullName" class="control-label"></label>
<input asp-for="Visitor.FullName" class="form-control" readonly value="@Model.Visitor.FullName" />
</div>
<div class="form-group">
<label asp-for="Visitor.Company" class="control-label"></label>
<input asp-for="Visitor.Company" class="form-control" readonly value="@Model.Visitor.Company" />
</div>
<div class="form-group">
<label asp-for="Escort.EmployeeId" class="control-label"></label>
<input asp-for="Escort.EmployeeId" class="form-control" readonly value="@Model.Escort.EmployeeId" />
</div>
<div class="form-group">
<label asp-for="Escort.FullName" class="control-label"></label>
<input asp-for="Escort.FullName" class="form-control" readonly value="@Model.Escort.FullName" />
</div>
<div class="form-group">
<label asp-for="CheckIn.Time" class="control-label"></label>
<input asp-for="CheckIn.Time" class="form-control" readonly type="text" value="@Model.CheckIn.Time.ToString("g")" />
</div>
<div class="form-group">
<label asp-for="CheckOut.ExpectedTime" class="control-label"></label>
<input asp-for="CheckOut.ExpectedTime" class="form-control" readonly type="text" value="@Model.CheckOut.ExpectedTime.ToString("g")" />
</div>
<div class="form-group">
<input asp-for="Visitor.LocationId" class="form-control" hidden value="@Model.Visitor.LocationId" />
</div>
<div class="form-group">
<input asp-for="Visitor.FirstName" class="form-control" hidden value="@Model.Visitor.FirstName" />
</div>
<div class="form-group">
<input asp-for="Visitor.LastName" class="form-control" hidden value="@Model.Visitor.LastName" />
</div>
<div class="form-group">
<input asp-for="Visitor.SignedIn" class="form-control" hidden value="@Model.Visitor.SignedIn" />
</div>
<div class="form-group">
<input asp-for="Escort.FirstName" class="form-control" hidden value="@Model.Escort.FirstName" />
</div>
<div class="form-group">
<input asp-for="Escort.LastName" class="form-control" hidden value="@Model.Escort.LastName" />
</div>
<div class="form-group">
<input asp-for="Escort.EmailAddress" class="form-control" hidden value="@Model.Escort.EmailAddress" />
</div>
<div class="form-group">
<input asp-for="Escort.Phone" class="form-control" hidden value="@Model.Escort.Phone" />
</div>
<div class="form-group text-center mt-4">
<input type="submit" class="btn btn-primary col-5" value="Confirm" />
<a class="btn btn-danger col-5 offset-1" asp-controller="Visitors" asp-action="SignIn" asp-route-LocationId=@Context.Request.Query["LocationId"]>Back</a>
</div>
</form>
</div>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
【问题讨论】:
标签: c# sql-server entity-framework entity-framework-core asp.net-core-mvc