郁闷的PP

博客园 首页 新随笔 联系 订阅 管理

好久没写了。接着前面的来:

一个小Forum Web程序示例,ASP.NET MVC Framework,总体结构介绍(Part 1)

一个小Forum Web程序示例,ASP.NET MVC Framework,TDD简介(Part 2)

上一部分写得太长太详细,这次争取描述清楚的前提下,写简短一点。

 

上部分中,简单介绍了TDD流程,并创建了一些测试,这部分我将进一步完善,开始实现真实的SqlFourmRepository。

另外简单介绍一个延迟加载的LazyList<T>和MVC分页很方便的PagedList<T>(末尾处有改进的PageList<T>)。

按照惯例,先放个数据库结构图:

image

还是一如既往的简单,使用了Membership,创建了数据库关系。

这里描述一下:Post表中的ParentId如果为Guid.Empty(00000000-0000-0000-0000-000000000000),表示这个帖子是主贴,如果为其他Post的Id,表示回帖,其他一概从简。

下面是当前的IForumRepository,定义了一些方法,并在SqlForumRepository中实现这些没有被实现的方法。

image 

打开dbml文件,把需要用的几个表,都拖进去:

image

再看看我们之前的通用Models,这两种实体是不同的,在ForumService中,需要的是Models.Post和Models.Category,在SqlForumRepository中,我们需要查询LinqToSqlClasses实体,而返回的却是Model.Post(需要做一个转换)。

image

以AddPost(Models.Post post)为例,现在可以开始编写测试了:

image

这个测试中,创建了一个Post,并尝试提取它(GetPost方法我之前已经实现了)。

在Assert中,严谨的做法应该是对比这两个对象(创建的post和从数据库中提取的actual),不过Assert.AreEqual方法对比引用类型总是会亮灯,只有重写Post类的Equals方法,在里面分别对比每个属性才行;或者在测试中一个一个去Assert,这样太麻烦了。仅仅是为了测试重写Equals方法,我的做法是:调试这个测试方法,在调试的时候查看是否有漏掉的,没有问题的话,就简单的Assert一下。(不知道正确否?请各位前辈们指点。)

现在运行这个测试,亮灯,因为方法还没实现。

image

现在实现这个方法,测试,通过了。

现在如法炮制,实现IForumService的其他所有方法,并保证测试通过就行了。

 

注意:

image 

含有一个Models.Post的列表,我这里使用的是LazyList<Models.Post>类型(有关LazyList请看这里:Lazy Loading With The LazyList),它不会像ToList()那样被执行,仍然维持IQueryable状态,不会立即查询数据库,LazyList很适合用来处理一对多延迟查询的情况。

这样的查询像这样写就完全OK了(这里的GetPost同样返回的IQueryable<Models.Post>):

image

还有一种多对一的情况。通过Post反向查找Category,如果仍然用LazyList会让人和迷惑,所以我也很迷惑,写个延迟加载的Category?晕乎乎。所以就干脆省略掉,Post中始终是有CategoryId的。

 

LazyList<Post>的分页怎么办?

这里有个古老的MVC分页PagedList<T>,在很早之前Scott Hanselman的视频里就是用了这个类,不过它是继承List<T>的,所以它不会被延迟执行。在我们这个方案中,它不应该属于SqlForumRepository,不过这里顺带一起介绍了吧。

这个PagedList<T>(原版)有点小bug(判断分页那里),嘿嘿,还有一种改进型的PagedList<T>,因为不记得在哪里找到的了,所以我直接贴出来:

    public interface IPagedList
    
{
        
int TotalCount getset; } 

        
int PageIndex getset; } 

        
int PageSize getset; } 

        
bool IsPreviousPage get; } 

        
bool IsNextPage get; }
    }
 

    
public class PagedList<T> : List<T>
    
{
        
public PagedList(IQueryable<T> source, int index, int pageSize)
        
{
            TotalCount 
= source.Count();
            PageSize 
= pageSize;
            PageIndex 
= index;
            AddRange(source.Skip((index 
- 1)*pageSize).Take(pageSize).ToList()); 

            
int pageResult = 0;
            
for (int counter = 1; pageResult < TotalCount; counter++)
            
{
                pageResult 
= counter*PageSize;
                TotalPages 
= counter;
            }

        }
 

        
public int TotalPages getset; } 

        
public int TotalCount getset; } 

        
public int PageIndex getset; } 

        
public int PageSize getset; } 

        
public bool HasPreviousPage
        
{
            
get return (PageIndex > 1); }
        }
 

        
public bool HasNextPage
        
{
            
get return (PageIndex*PageSize) < TotalCount; }
        }

    }
 

    
public static class Pagination
    
{
        
public static PagedList<T> ToPagedList<T>(this IQueryable<T> source, int index, int pageSize)
        
{
            
return new PagedList<T>(source, index, pageSize);
        }
 

        
public static PagedList<T> ToPagedList<T>(this IQueryable<T> source, int index)
        
{
            
return new PagedList<T>(source, index, 10);
        }
 

        
public static PagedList<T> ToPagedList<T>(this LazyList<T> source, int index, int pageSize)
        
{
            
return new PagedList<T>(source.AsQueryable(), index, pageSize);
        }
 

        
public static PagedList<T> ToPagedList<T>(this LazyList<T> source, int index)
        
{
            
return new PagedList<T>(source.AsQueryable(), index, 10);
        }

    }
 

改进版的首先是让页面从1开始,而不是0开始,让用户不会因为第一页是0而迷惑,第二是改变原先的IsNextPage方法名称为HasNextPage,我这里采用的改进版,并添加了两个针对LazyList的扩展方法。

暂时写到这里吧,感觉好像讲得不是很明白。ForumService没什么写头,好像剩下的就只有Controller和Membership了,介绍这方面的帖子很多,我想通过TDD(发挥MVC的优势)这样的角度来写吧,并和大家探讨一下使用Moq测试框架。

posted on 2008-10-04 15:54  郁闷的PP  阅读(2499)  评论(7编辑  收藏  举报