Razor视图模型支持 @model来初始化页面对象类型,比如:
也可以是一个支持迭代的公开枚举器:
当我们只关注对一个实体类进行呈现时,MVC 3.0的实现非常给力,Controller层只需要两行代码:
ToList()方法返回的是List<T>集合,它实现(Implements)了接口IEnumerable<out T>,所以var型变量traveller被传递到View层时,可采用foreach进行遍历:
再强大的框架,也只是把简单的事变得更简单,而问题一旦稍变复杂,多半都要靠聪明的大脑来解决,我挺喜欢去42区逛,其首页的类似微博的即时信息功能挺有意思;好歹自己也是做BS开发的,于是就采用MVC 3.0模拟一个玩玩。
其业务模型大概可以这样描述:已登录会员可以发表一条碎碎念(文字限定142),与之相随的图片数量不限定,同时可以被别的会员回复。从该描述中提取出实体对象:会员(Traveller)、碎碎念(Chat)、碎碎念图片(ChatImage)、碎碎念回复(ChatReply)
来自VS2010的免费图片:
很明显,实体Chat的主键字段ChatID关联起了实体ChatImage(1对多)和实体ChatReply(1对多)。
Linq to SQL该ORM框架会自动把数据库表一一映射为同名实体类,它们就像筑造楼房的砖瓦一样,成为各种业务模型组装的最为基本的对象。基于上述分析,显然发表碎碎念这一业务模型包含三个最基本的实体类:Chat、ChatImage、ChatReply,为了更好地表述,将该业务模型命名为ChatIntegration,并定义一个 ViewModel模式类来进行封装:
上述代码表明,单个碎碎念业务模型包含着一个碎碎念主体,和若干图片,以及若干回复。
一般来讲,模型(Model)在项目中往往就是起到一个承上启下的作用,如同小学时老师教我们八股式的写作文一般:先开头,接着铺述一段,然后作一个承上启下的段落,随之进入下一段的描写,最后以一个总结段结尾。这里的业务模型(ChatIntegration)同理,它先捞取数据库中的数据(基于Linq to SQL),将其存储在该实体中,然后抛给View层的页面,通过Razor引擎将其遍历呈现出来。
如前所述,接下来会做两件事:先往下层看,瞧一下处于中间的Model是如何向数据库捞取数据;然后再抬头仰视,看看Model把数据抛给View后如何遍历数据。
(一.)往下层看,按MVC 3.0的"分离关注点"思想,对于访问数据库的代码应该采用Repository设计模式,使得Controller层中的Action仅需调用Repository层中的相关函数就可得到数据集,从而很顺畅地将函数返回值传给View层,虽然"约定大于配置"很重要,但只要我的变动尚未破坏MVC架构,姑且就"耦合"一下吧,我会把访问数据库的代码直接写在名为Index的Action中:
通过声明式的Linq查询,我们得到了目前数据库中所有的碎碎念记录(实际中想必要根据时间过滤[比如查询最近一周]、并分页呈现,这里都忽略),没有更多的代码了。大家会看到在基于内联接的Linq查询的后半段,可直接定义(select new ChatIntegation)每一个碎碎念模型中的属性值。只要搞定一个ChatIntegation的赋值,那么基于泛型集合的chatIntegrationList都会统统接纳(隐式执行),最终作为View(object model)的参数传给视图层。
(二.)抬头仰视,视图层会接受到我们载着满满数据的业务模型(ChatIntegation):
接下来,业务模型ChatIntegation集合至少需要一次foreach遍历,用以将每一个ChatIntegation提取出来作进一步处理。就像我们在Controller层对数据作组装一样,只要对一个模型进行编码,那么基于泛型集合的每一个元素都会受到影响。
显然,第一次的遍历会在ChatIntegation中取到三个属性:ChatHeader(碎碎念)、ChatImages(图片)、ChatReplys(回复),
发现了图片和回复分别都是泛型集合,于是对他们二位再分别作第二层foreach遍历。
最后呈现的效果便是:
一个Demo下来,真正需要手写的代码仍不足50行,理解还是最为重要。