如标题所示,我在返回包含模型列表作为值之一的模型时遇到问题。目标是包含一些键值以及用户列表和报告列表的页面模型。但返回后,要么只有列表值为空,要么整个模型已使用默认值重新制作。
报表视图模型:
namespace DataLibrary.Models
{
public class ReportViewModel
{
[Key]
public string Id { get; set; } = "0";
public string Admin { get; set; } = "n";
public List<ReportModel> Reports { get; set; }
public List<UserModel> Users { get; set; }
public DateTime Start { get; set; } = DateTime.Now.AddDays(-(DateTime.Now.DayOfWeek - DayOfWeek.Monday));
public DateTime End { get; set; } = DateTime.Now;
}
}
UserModel 和 ReportModel 都有大量的 string、BitArray 和 int 值。我为下面的故障排除创建了一个更简单的测试视图。这主要是为了测试仅返回整个列表而不进行任何编辑,因为它应该更容易,但这仍然证明是无效的:
@model DataLibrary.Models.ReportViewModel
@{
ViewData["Title"] = "Report1";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<form asp-action="SelectDate">
<div class="container">
<div class="row form-group">
<input type="hidden" asp-for="@Model.Reports" />
<input type="hidden" asp-for="@Model.Users" />
<div class="col-4">
<input asp-for="@Model.Start"></input>
</div>
<div class="col-4">
<input asp-for="@Model.End"></input>
</div>
<div class="col-4">
<input type="submit" value="Select Date Range" class="btn btn-primary" />
</div>
</div>
@if (Model.Admin != "n")
{
<div class="row">
<input asp-for="Admin" hidden="hidden" />
@{
var perm1 = new Dictionary<string, string>
{
{"id", Model.Id},
{"adm", Model.Admin}
};
}
<div class="col-4"><a asp-controller="Timesheet" asp-action="AuthAll" asp-all-route-data="perm1" class="btn btn-primary">Authorize All</a></div>
<div class="col-4">
<select asp-for="Id">
@for (int e = 0; e < Model.Users.Count; e++)
{
if (Model.Users[e].USER_ID == Model.Id)
{
<option value="@Model.Users[e].USER_ID" selected="selected">@Model.Users[e].USER_FIRST_NAME @Model.Users[e].USER_LAST_NAME</option>
}
else
{
<option value="@Model.Users[e].USER_ID">@Model.Users[e].USER_FIRST_NAME @Model.Users[e].USER_LAST_NAME</option>
}
}
</select>
<input type="submit" value="Select User" class="btn btn-primary" />
</div>
</div>
}
</div>
</form>
在实际视图中,我最初使用 foreach 但看到其他人说这不是一个好方法,而基本的 for 循环效果更好?因此,我目前使用下面的内容作为完整视图/编辑报告列表中的模型,但使用上面的内容来解决不返回列表和正确值的问题。提交以下内容后,发送到控制器的模型中的报告列表具有正确的条目数,但所有值均为 NULL。 foreach 和 for 循环版本都是这种情况:
@model DataLibrary.Models.ReportViewModel
@{
}
<form asp-action="SelectDate">
<div class="container">
<div class="row form-group">
<div class="col-4">
<input asp-for="@Model.Start"></input>
</div>
<div class="col-4">
<input asp-for="@Model.End"></input>
</div>
<div class="col-4">
<input type="submit" value="Select Date Range" class="btn btn-primary" />
</div>
</div>
@if(Model.Admin != "n")
{
<div class = "row">
<input asp-for="Admin" hidden="hidden"/>
@{var perm1 = new Dictionary<string, string>
{
{"id", Model.Id},
{"adm", Model.Admin}
};}
<div class="col-4"><a asp-controller="Timesheet" asp-action="AuthAll" asp-all-route-data="perm1" class="btn btn-primary">Authorize All</a></div>
<div class="col-4">
<select asp-for="Id">
@for(int e = 0; e< Model.Users.Count; e++)
{
if (Model.Users[e].USER_ID == Model.Id)
{
<option value="@Model.Users[e].USER_ID" selected="selected">@Model.Users[e].USER_FIRST_NAME @Model.Users[e].USER_LAST_NAME</option>
}
else
{
<option value="@Model.Users[e].USER_ID">@Model.Users[e].USER_FIRST_NAME @Model.Users[e].USER_LAST_NAME</option>
}
}
@* @foreach (var user in Model.Users)
{
if (user.USER_ID == Model.Id)
{
<option value="@user.USER_ID" selected="selected">@user.USER_FIRST_NAME @user.USER_LAST_NAME</option>
}
else
{
<option value="@user.USER_ID">@user.USER_FIRST_NAME @user.USER_LAST_NAME</option>
}
} *@
</select>
<!-- send model and select based on values, date, user, etc-->
<input type="submit" value="Select User" class="btn btn-primary" />
</div>
</div>
}
</div>
</form>
<form asp-action="Update">
<div class="form-group">
<table class="ReportTable " >
<thead>
<tr class="ReportRows">
<th>
@Html.DisplayName("Date")
</th>
<th>
@Html.DisplayName("Attendance")
</th>
<th>
@Html.DisplayName("Hours")
</th>
<th>
@Html.DisplayName("Over")
</th>
<th>
@Html.DisplayName("Update/Unauth")
</th>
<th>
@Html.DisplayName("Authenticate")
</th>
<th>
@Html.DisplayName("Delete")
</th>
</tr>
</thead>
<tbody>
<input asp-for="@Model.Start" type="hidden"></input>
<input asp-for="@Model.End" type="hidden"></input>
<input type="hidden" value="@Model.Reports" />
<input type="hidden" value="@Model.Users" />
@for (int i = 0; i< Model.Reports.Count; i++)
{
<div class="form-group">
<tr class="ReportRows">
@* <input type="hidden" value="@Model.Reports[i].SALARIED1" />
<input type="hidden" value="@Model.Reports[i].PRESENT1" />
<input type="hidden" value="@Model.Reports[i].PRESENT_AFTERNOON1" /> *@
<th>
@Html.DisplayName(Model.Reports[i].DATE1.ToString())
</th>
<th>
@if (Model.Reports[i].SALARIED1[0] == true)
{
//if salaried show am pm
<input type="checkbox" asp-for="@Model.Reports[i].PRESENT1[0]" />
<input type="checkbox" asp-for="@Model.Reports[i].PRESENT_AFTERNOON1[0]" />
}
else
{
//TimeOnly t = TimeOnly.FromDateTime(entry.CLOCKIN1);
<input type="text" asp-for="@Model.Reports[i].CLOCKIN1" />
<input type="text" asp-for="@Model.Reports[i].CLOCKOUT1" />
// if not salaried show times
}
</th>
<th>
@if (Model.Reports[i].SALARIED1[0] == true)
{
@Html.DisplayName("N/A")
}
else
{
@Html.DisplayName(Model.Reports[i].totalminute_work1.ToString())
}
</th>
<th>
@if (Model.Reports[i].SALARIED1[0] == true)
{
@Html.DisplayName("N/A")
}
else
{
@Html.DisplayName(Model.Reports[i].over_time1.ToString())
}
</th>
<th>
@if (Model.Reports[i].AUTHORIZED1 != null && Model.Reports[i].AUTHORIZED1[0] == true)
{
// display button to unauth
var perm = new Dictionary<string, string>
{
{"Date", Model.Reports[i].DATE1.ToString()},
{"id", Model.Reports[i].USER_ID1},
{"tsid", Model.Reports[i].ID1.ToString()},
{"adm", Model.Admin }
};
<a asp-controller="Timesheet" asp-action="UnAuth" asp-all-route-data="perm" class="btn">UnAuth</a>
@* <a asp-controller="Timesheet" asp-action="Unauth" class="btn">UnAuth</a> *@
}
else
{
var perm4 = new Dictionary<string, string>
{
{"Date", Model.Reports[i].DATE1.ToString()},
{"Uname", Model.Reports[i].USER_ID1},
{"tsid", Model.Reports[i].ID1.ToString()},
{"adm", Model.Admin } ,
{"p1", Model.Reports[i].PRESENT1[0].ToString()}
//,
//{"p2", Model.Reports[i].PRESENT_AFTERNOON1[0].ToString()}
};
// update times button
<a asp-controller="Timesheet" asp-action="Update" asp-all-route-data="perm4" class="btn">Update</a>
<button type="submit" class="btn btn-primary">Update</button>
}
</th>
<th>
@if (Model.Reports[i].AUTHORIZED1 != null && Model.Reports[i].AUTHORIZED1[0] == true)
{
}
else
{
var perm = new Dictionary<string, string>
{
{"Date", Model.Reports[i].DATE1.ToString()},
{"Uname", Model.Reports[i].USER_ID1},
{"t", null},
{"adm", Model.Admin }
};
<a asp-controller="Timesheet" asp-action="Auth" asp-all-route-data="perm" class="btn">Auth</a>
@* asp - Date = "@entry.DATE1" asp - Uname = "@entry.USER_ID1" asp - t = "" asp - model = "@Model" *@
@* @Html.ActionLink("Auth", "Auth", new{Date = entry.DATE1}, new{Uname = entry.USER_ID1}, new {t = ""}) *@
}
</th>
<th>
@if (Model.Reports[i].AUTHORIZED1 != null && Model.Reports[i].AUTHORIZED1[0] == true)
{
}
else
{
var perm3 = new Dictionary<string, string>
{
{"Date", Model.Reports[i].DATE1.ToString()},
{"Uname", Model.Reports[i].USER_ID1},
{"tsid", Model.Reports[i].ID1.ToString()},
{"adm", Model.Admin }
};
<a asp-controller="Timesheet" asp-action="DeleteClock" asp-all-route-data="perm3" class="btn">Delete</a>
}
</th>
</tr>
</div>
}
</tbody>
</table>
</div>
</form>
控制器部分非常简单:
public IActionResult Report1()
{
if (HttpContext.Session.GetString("User") != null)
{
// get info here and pass into view based on session name
// need to create option for admins to select different users, and allow all users to select different
// date range
ReportViewModel model = new ReportViewModel();
List<ReportModel> reports = //redacted database code;
// session to stand in for validation until I learn that more thoroughly.
if (HttpContext.Session.GetString("Admin") != "n")
{
entries = _db.user.ToList();
users = entries.ToList();
}
model.Id = HttpContext.Session.GetString("User");
model.Reports = reports;
model.Users = users;
model.Admin = HttpContext.Session.GetString("Admin");
return View(model);
}
else
{
return RedirectToAction("Login");
}
}
[HttpPost]
public IActionResult Report1(ReportViewModel model)
{
string test = "";
return View(model);
}
我很抱歉,因为我仍在学习很多关于这个系统的知识,并且认为这种布局将有助于良好的实践,但已经遇到了这个障碍。
如上所述,我尝试创建一个简单版本的视图,只返回发送的模型,除了非列表参数之外,没有进行太多更改,这仍然导致列表为空。我尝试将所有值的 name="" 属性设置为原始模型上列出的值,但无济于事。我不确定是什么原因导致此时不返回已填写的列表的问题。不幸的是,其他问题似乎触及了这个主题,但我能找到的最接近的问题似乎没有提供任何进一步的见解。 看着类似的帖子,我似乎缺少表单控制?看了这么久,我有点累了,所以我稍后再回到这个。
以任何形式存在于客户端浏览器上。控制器将模型发送到服务器视图引擎,以组成 HTML 发送到客户端浏览器。当客户端浏览器提交表单时,MVC 的 JavaScript 会通过 DOM 查找它可以识别为可能需要返回到服务器的值。没有@Model 可以发回。 MVC 掩盖了此行为,使其看起来像是向客户端发送对象模型并在提交时返回该对象模型,但实际上并没有这样做。在表单提交上,它本质上传递的是字符串值,服务器随后将尝试组合对象的新副本,无论是来自通过 POST 提交的各种值的实体还是视图模型。 这最终意味着在表单提交上将复杂的对象图传递回服务器变得相当笨拙。为了将相关对象传递回服务器,每个必需的相关实体上的每个必需属性都需要有一个提交 JavaScript 可以解析的输入控件,并且 mVC 将识别该输入控件以便能够重新组合一个新的填充的当它收到所有这些字段时,该模型的副本。不幸的是这样的代码:
<input type="hidden" asp-for="@Model.Reports" />
...如果您希望报告在 POST 上返回到服务器,那么这还不够。您需要让页面迭代 @Model.Reports 来为您想要发回的任何/所有属性创建隐藏输入。
当涉及到将 MVC 与实体框架之类的数据结合使用时,我不建议尝试期望将实体传递到视图或从视图中传递出来,而是只传递视图需要的内容,并只接受视图所包含的值编辑/引用将返回,然后加载表单上的实体,提交以在验证后复制相关更新。它还有助于将更新操作规划为相对原子的,以便增量应用更改,而不是涉及跨大量相关实体的大量更改的大型操作。