写这文的缘由是一个决定走前端路的同学在写后端代码挣扎时想到给后来的同学减少些痛苦。此文偏重于分享当视图需要不止一张表的数据时,控制器得到的数据该如何传递到前端视图。
在.NET mvc的架构中,前端页面需要用到一张表或多张表的数据,这其中产生的操作是不同的。视图需要显示各种无法直接映射到域模型中定义的模型。——《ASP.NET MVC程序开发》。举个例子说,我项目中的教师个人中心页需要展示教师表的信息和教师详情表的信息,他们是存在于两个不同的数据模型中。且由于MVC机制的原因,view不能同时引用多个model,controller中的方法也不能同时传多个类到view中。
就我掌握的方法而言,有以下几种:为页面定制需要的viewmodel;利用数据库模型中的导航属性;在数据库层面创建好需要数据的视图;使用viewBag或viewData或TempData。
显然,提到的前三种都是使用强类型的方法,最后一种是弱类型的方法。接下来我们来一一了解这些方法的具体解决过程。
1.定制viewmodel,这是比较常见的一种做法。拿我的项目来说,我的首页需要呈现诸如家教单、教员和教员详情等信息,然后我定制了如下的viewmodel,这就好比是是一个从数据库生成的数据模型,但只不过是我们手敲代码而成的。在控制器中具体使用中,就可以把viewmodel里面的属性当做字段使用,从数据库获得的数据逐个放入其中,再把类放到定制viewmodel中,就可以安全稳定地传递给前端视图。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Model;
namespace Tutor.UI.ViewModels
{
public class IndexVM
{
public IEnumerable<task> task
{
get; set;
}
public IEnumerable<teacher> teacher
{
get; set;
}
...
}
}
viewmodel代码
var grades = gradeSer.GetModels(b => b.Grade_id !=0);
var tasks = taskSer.GetAll().Take(5);
IndexVM indexvm = new ViewModels.IndexVM();
indexvm.grade = grades;
indexvm.task = tasks;
return View(indexvm);
控制器部分代码
2.利用数据库的导航属性。先说评价,用时一时爽,但有局限性。我具体使用到的例子,我首页的家教单展示时,主要数据来自task表,但仍需要学员表中的学员姓名(家教单由学员发布,student表是task表的主键表),这个时候后台不需要查询学员的相关数据,前台也可以很轻松通过导航属性获得学员数据,见下方红色代码处。这样用简直爽到不行。那局限性呢?其局限性在于,并不是正反向的外键关系都可以利用导航属性,而只能是正向的外键才能使用。见下图实例,后台查询了task的数据传到前台时,此时可以使用导航属性访问学员表中的数据。但如果如右方查询了teacher的数据,希望通过导航属性访问teacherinfo中的数据时,那将会失效。其中原理,我们老师给我们举了一个很形象的例子,子代对应的父代只有一个,但父代对应或许并不只有一个。
@foreach(var item in Model.task)
{
<div class="singlecase">
<div class="Ttop">
<div>@item.Student.Suser_name 急需家教</div>
<div>辅导 @item.Subject</div>
<div>
<strong>面议</strong>
</div>
</div>
...
</div>
}
3.在数据创建视图,原理跟viewmodel一样,只不过在不同的位置实现,使用创建视图的方法能够较好的解决导航属性的局限性问题。viewmodel是在项目中将多个类放到一块,而创建视图则是在数据库层面将要展示的数据放到一个虚表里,但在映射数据模型时,视图跟表并没有什么不同。
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码已从模板生成。
//
// 手动更改此文件可能导致应用程序出现意外的行为。
// 如果重新生成代码,将覆盖对此文件的手动更改。
// </auto-generated>
//------------------------------------------------------------------------------
namespace Model
{
using System;
using System.Collections.Generic;
public partial class Tuser
{
public string Videos { get; set; }
public int Teacher_id { get; set; }
public string Tuser_name { get; set; }
public string Tmail { get; set; }
public string Ident_photo { get; set; }
}
}
4.使用ViewData或ViewBag或TempData,