c# - 如何从 MVC 中的 3 个表中获取视图中的结果
问题描述
我有 3 个相关表,Table1 => Table2 => Table3 关系就是这种类型。
我有来自 Table1 和 Table2 的数据,因为我有来自 Table1 的模型要显示,现在我的问题是 Table3,我无法获取要显示的数据。我需要详细显示数据,我的项目是用于民意调查的。
- 表 1 = 问题(关键是 QID)
- 表 2 = 答案选项(关键 ANID,q_ID 是问题的关键)
- 表 3 = 结果(计数投票)(键是 RID,ans_ID 是 AnswerOption 的键)
控制器是默认代码:
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Questions questions= db.Questions.Find(id);
if (questions== null)
{
return HttpNotFound();
}
return View(questions);
}
查看代码:
@foreach (var item in Model.Answers)
{
if (item != null)
{
<tr>
<td>
@Html.DisplayFor(x => item.AnswerName)
</td>
<td>
@Html.DisplayFor(x => item.Results.Result)
</td>
</tr>
}
模型问题:
public class Questions
{
public Questions()
{
Answers= new HashSet<Answers>();
}
[Key]
public int QID { get; set; }
public string Prasanje { get; set; }
public bool pubOdg { get; set; }
public int? avtor { get; set; }
public virtual ICollection<Answers> Answers { get; set; }
[ForeignKey("avtor")]
public virtual tbl_useri tbl_useri { get; set; }
}
模型答案:
public Answers()
{
Results= new HashSet<Results>();
}
[Key]
public int ANID{ get; set; }
public int q_ID{ get; set; }
public string Odgovor { get; set; }
public string kreator { get; set; }
public int? rCount { get; set; }
[ForeignKey("q_ID")]
public virtual Questions Questions{ get; set; }
public virtual ICollection<Results> Results{ get; set; }
模型结果:
public class Results
{
[Key]
public int RID{ get; set; }
public int ans_ID{ get; set; }
public int Result{ get; set; }
[ForeignKey("ans_ID")]
public virtual Answers Answers { get; set; }
}
解决方案
我将从一些定义开始:
- 视图模型是一种表示特定于特定渲染视图的数据的类型。控制器动作应该创建这个对象并用加载的数据填充它,然后将它传递给视图。
- 这是 ASP.NET MVC 和 ASP.NET Core 中关注点分离的核心,也是所有现代(2005 年后)Web 编程框架中的常见设计模式。
- 将其与将数据库代码与 HTML 混合的老式 PHP/CGI/Classic ASP 编程进行比较。
- 在 Web 编程中,View-Model 通常是不可观察的、不可变的和短暂的对象,仅在 HTTP 请求的生命周期内持续存在。而在桌面编程(如 WPF、UWP XAML 等)中,视图模型通常是可观察的、可变的和长期存在的)。
- 模型类(不同于view-model )或实体类是一个对象,表示来自您的后备存储数据库的数据。(忽略 Razor 使用关键字来表示视图模型的事实)。
@model
(令我失望和恼火的是,大多数 ASP.NET MVC 和 ASP.NET Core 的初学者级教程仍然向用户介绍使用 Entity Framework 实体类型作为视图模型的反模式。这些教程应该教读者使用单独的视图模型以避免像此 OP 那样引导读者走错路并最终造成混淆。使用 EF 实体作为视图模型也会导致安全问题,因为它允许恶意用户在密码不足的情况下重置其他用户的密码(例如)输入请求的验证([BindNever]
例如,这是为了什么)。我的意思是:只是不要。)
回到正题:
如果这是一个单向视图(即您只显示数据库中的数据而不允许用户在 a 中编辑该数据<form>
),那么定义一个新类作为您的视图模型并使用您的实体数据作为属性填充它。
在你的情况下,你的控制器动作是QuestionsController::Details
,所以我有这个:
public class DetailsViewModel
{
// One-way members:
[BindNever]
public String PageTitle { get; internal set; }
public Question TheQuestion { get; internal set; }
public List<Answer> TheAnswers { get; internal set; }
// Two-way members:
// (you don't have any forms, so this area is empty)
}
然后修改您的控制器操作以创建、填充并返回此视图模型类型:
public async IActionResult Details(Int32? id)
{
if( id == null ) return this.NotFound();
Question question = await this.db.Questions.SingleOrDefaultAsync( id.Value );
if( question == null ) return this.NotFound();
DetailsViewModel vm = new DetailsViewModel()
{
PageTitle = "Details for " + question.Title,
TheQuestion = question,
TheAnswers = await this.db.Answers.Where( q => a.Question == question ).ToListAsync()
};
return this.View( model: vm );
}
并更改您的 Razor 视图以使用此视图模型:
@model DetailsViewModel
<html>
<head>
<title>@Model.PageTitle</title>
</head>
<body>
<h2>Question</h2>
<p>@Model.TheQuestion.QuestionText</p>
<h2>Answers</h2>
@foreach( Answer ans in this.Model.TheAnswers )
{
<h3>Answer @ans.Name</h3>
@foreach( Result result in ans.Results )
{
<h3>@result.Name</h3>
}
}
</body>
</html>
如果您想允许用户在 a 中编辑数据,POST
那么<form>
您需要为您希望用户能够编辑的每个表行定义新的类。但这超出了您原始问题的范围,但请在线搜索“ASP.NET mvc 模型绑定”以获取更多详细信息。
推荐阅读
- kubernetes - 从客户端发送的所有持久 Http 请求是否都被路由到 kubernetes 中的同一个 pod?
- algorithm - 对于未排序的数组,线性搜索何时优于二分搜索?哪种排序算法与二分搜索一起首先对数组进行排序?
- ios - Swift:获取线程 1:发出 SIGABRT 信号,但我的所有插座都已连接
- vim - 使用 vim 编辑剪贴板中的内容,然后将其放在命令行上执行
- html - 检索 a 的确切 X/Y 值
- 无论使用 Typescript 在何处单击鼠标
- lucene - 如何在 graphdb lucene 连接器中使用属性路径
- javascript - Gatsby WordPress Source - 不使用时被 graphql 忽略的灵活内容布局
- python-3.x - 这是子集和解决方案吗?
- java - 使用同一会话的多个事务的示例
- javascript - 多个表单在最后一个表单上提交 PHP