ASP.NET MVC 3.0 Razor视图如何展示多实体
Razor视图模型支持@model来初始化页面对象类型,比如:
1 @model FlashTravel.Models.Traveller>
也可以是一个支持迭代的公开枚举器:
1 @model IEnumerable<FlashTravel.Models.Traveller>
当我们只关注对一个实体类进行呈现时,MVC 3.0的实现非常给力,Controller层只需要两行代码:
public ActionResult Index()
{
var traveller = dbFlashTravel.Traveller.ToList();
return View(traveller);
}
ToList()方法返回的是List<T>集合,它实现(Implements)了接口IEnumerable<out T>,所以var型变量traveller被传递到View层时,可采用foreach进行遍历:
@foreach (var item in Model) {
//......
}
再强大的框架,也只是把简单的事变得更简单,而问题一旦稍变复杂,多半都要靠聪明的大脑来解决,我挺喜欢去42区逛,其首页的类似微博的即时信息功能挺有意思;好歹自己也是做BS开发的,于是就采用MVC 3.0模拟一个玩玩。
其业务模型大概可以这样描述:已登录会员可以发表一条碎碎念(文字限定142),与之相随的图片数量不限定(测试时只提供一张),同时可以被别的会员回复。从该描述中提取出最基本的实体对象:会员(Traveller)、碎碎念(Chat)、碎碎念图片(ChatImage)、碎碎念回复(ChatReply)
来自VS2010的免费图片:
很明显,实体Chat的主键字段ChatID关联起了实体ChatImage(1对多)和实体ChatReply(1对多)。
Linq to SQL该ORM框架会自动把数据库表一一映射为同名实体类(EF4.0道理亦然),这些实体类就像筑造楼房的砖瓦一样,成为各种业务模型组装的最为基本的对象。基于上述分析,显然发表碎碎念这一业务模型有三个最基本的实体类参与:Chat、ChatImage、ChatReply,为了更好地表述他们,我将该业务模型命名为ChatIntegration(碎碎念综合),并采用一个视图模型模式(ViewModel Pattern)类来进行封装:
namespace FlashTravel.ViewModels
{
/// <summary>
/// 碎碎念综合
/// </summary>
public class ChatIntegration
{
/// <summary>
/// 碎碎念
/// </summary>
public Chat ChatHeader { set; get; }
/// <summary>
/// 碎碎念图片
/// </summary>
public IList<ChatImage> ChatImages { set; get; }
/// <summary>
/// 碎碎念回复
/// </summary>
public IList<ChatReply> ChatReplys { set; get; }
}
}
上述代码表明,单个碎碎念业务模型包含着一个碎碎念主体叫ChatHeader,和若干图片(复数),以及若干回复(复数)。
一般来讲,Model层在项目中往往就是起到一个承上启下的作用(MVC或传统的三层),如同小学时老师教我们八股式的写作文一般:先开头,接着铺述一段,然后作一个承上启下的段落,随之进入下一段的描写,最后以一个总结段结尾。这里的业务模型(ChatIntegration)同理:第一段,在Controller层先捞取数据库中的数据(基于Linq to SQL)将其存储在业务模型中;第二段,业务模型将被抛给View层的页面,通过Razor引擎遍历呈现。
如前所述,接下来会做两件事:先往下层看,瞧一下处于中间的业务模型(ChatIntegration)是如何得到数据库数据;然后再抬头仰视,看看业务模型(ChatIntegration)被抛给View后如何遍历数据。
(一.)往下层看,按MVC 3.0的"分离关注点"思想,对于访问数据库的代码应该采用Repository设计模式,使得Controller层中的Action仅需调用Repository层中的相关函数就可得到数据集,从而很顺畅地将函数返回值传给View层,虽然"约定大于配置"很重要,但只要我的精简尚未破坏MVC架构,姑且就"耦合"一下吧,我会把访问数据库的代码直接写在名为Index的Action中:
public class ChatController : Controller
{
FlashTravelDataContext dbFlashTravel = new FlashTravelDataContext();
public ActionResult Index()
{
//查询所有碎碎念
var chatIntegrationList = from chat in dbFlashTravel.Chat
join chatImage in dbFlashTravel.ChatImage
on chat.ChatID equals chatImage.ChatID into chatImages
join chatReply in dbFlashTravel.ChatReply
on chat.ChatID equals chatReply.ChatID into chatReplys
select new ChatIntegration
{
ChatHeader = chat,
ChatImages = chatImages.ToList(),
ChatReplys = chatReplys.ToList()
};
return View(chatIntegrationList);
}
}
通过声明式的Linq查询,我们得到了目前数据库中所有的碎碎念记录(实际中想必要根据时间进行过滤[比如只查询最近一周]、并分页呈现,这里都忽略),没有更多的代码了。大家会看到在基于内联接的Linq查询的后半段,可直接定义(select new ChatIntegation)每一个碎碎念模型中的属性值。只要搞定一个ChatIntegation的赋值,那么基于泛型集合的chatIntegrationList都会统统受到影响,最终它作为View(object model)的参数传给视图层。
(二.)抬头仰视,视图层会接受到我们载着满满数据的业务模型集合(ChatIntegation泛型集合):
1 @model IEnumerable<FlashTravel.ViewModels.ChatIntegration>
接下来,业务模型ChatIntegation集合至少需要一次foreach遍历,用以将每一个ChatIntegation提取出来作进一步处理。就像我们在Controller层对数据作组装一样,只要对一个业务模型进行编码,那么基于泛型集合的每一个元素都会受到影响。
显然,第一次的遍历会在每个一个元素ChatIntegation中取到三个属性:ChatHeader(碎碎念)、ChatImages(图片)、ChatReplys(回复),
发现图片和回复分别又是一个新的子泛型集合,于是对他们二位再分别作第二层foreach遍历: @{
ViewBag.Title = "Index";
}
<h2>
Index</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table>
@foreach (var item in Model)
{
<tr>
<td style="width: 150px; text-align: center;">
@item.ChatHeader.NickName
</td>
<td style="width: 350px; text-align: right;">
@item.ChatHeader.PublishTime
</td>
</tr>
<tr>
<td style="width: 150px; text-align: center;">
@foreach (var image in item.ChatImages)
{
<img alt="@image.ImageRemark" src="@image.ImageUrl" />
}
</td>
<td style="width: 350px; text-align: left;">
@item.ChatHeader.Content
</td>
</tr>
<tr>
<td colspan="2">
<br />
<span style="font-weight: bold;">FeedBack</span>
<hr />
</td>
</tr>
foreach (var reply in item.ChatReplys)
{
<tr>
<td colspan="2">
<table style="width: 100%;">
<tr>
<td>
@reply.PublishTime|@reply.NickName
</td>
</tr>
<tr>
<td>
@reply.Reply
</td>
</tr>
</table>
</td>
</tr>
}
}
</table>
最后呈现的效果便是:
<script></script>
一个Demo下来,真正需要手写的代码仍不足50行,编程方式的理解还是最为重要
摘自 不觉流年似水
相关新闻>>
- 发表评论
-
- 最新评论 更多>>