注册 | 登录 | 评论 | 订阅 | 关于

DbEntry 开发实践:Wiki 系统(三)

这几篇文章,是先发表在我的博客园blog上的,现在我的站点使用 DbEntry 升级完毕,也把这些文章贴回来

  书接上文,我们有了Show.aspx和Edit.aspx页面,现在应该开发历史记录功能了。

  不过,在做这个之前,我们先加入一个Default.aspx,用来转向到有参数的Show.aspx页面,省得每次要自己输入title参数:
<%@ Page Title="" Language="C#" MasterPageFile="~/Main.master" %>

<script runat="server">
    protected void Page_Load(object sender, EventArgs e)
    {
        Response.Redirect(new UrlBuilder("Show.aspx").Add("title", "Home").ToString());
    }
</script>

<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
</asp:Content>

  现在,我们来考虑历史记录问题。一般来说,我们只工作在最新的Wiki页之上,所以,我们需要另一个表来保存历史数据,就叫ArticleHistory吧,它和Article应该是一对多关系,隶属于Article,而且,它的Init方法应该接受一个Article作为参数,所以,代码如下:
namespace VisualWiki.Models
{
    public abstract class ArticleHistory : LinqObjectModel<ArticleHistory>
    {
        public abstract string Content { get; set; }

        [Index(ASC = false)]
        public abstract DateTime CreatedOn { get; set; }

        [BelongsTo]
        public abstract Article Article { get; set; }

        public ArticleHistory Init(Article article)
        {
            Content = article.Content;
            CreatedOn = article.SavedOn;
            return this;
        }
    }
}

  然后Article类也需要相应的修改,应该增加HasMany的ArticleHistory列表:
[HasMany(OrderBy = "CreatedOn DESC, Id DESC")]
public abstract IList<ArticleHistory> History { get; set; }

  然后,在SaveArticle函数里,应该同时保存历史数据,既然SaveArticle函数需要修改,我们还是先来修改单元测试吧:
[Test]
public void TestSaveArticle()
{
    Article.SaveArticle("title", "whatever it is");
    var o1 = Article.FindByTitle("title");
    Assert.IsNotNull(o1);
    Assert.AreEqual("whatever it is", o1.Content);
    Assert.AreEqual(0, o1.History.Count);

    Article.SaveArticle("title", "hello, I'm coming");
    var o2 = Article.FindByTitle("title");
    Assert.IsNotNull(o2);
    Assert.AreEqual("hello, I'm coming", o2.Content);
    Assert.AreEqual(1, o2.History.Count);
    Assert.AreEqual("whatever it is", o2.History[0].Content);
}

  现在运行单元测试,显示失败,我们修改SaveArticle函数如下:
public static void SaveArticle(string title, string content)
{
    var article = FindByTitle(title);
    if(article == null)
    {
        article = New.Init(title, content);
    }
    else
    {
        article.History.Add(ArticleHistory.New.Init(article));
        article.Content = content;
    }
    article.Save();
}

  再次运行单元测试,显示成功,业务逻辑正确。现在我们需要一个页面来显示历史,这个历史页面,同样接受一个title参数,而且使用GridView来显示其创建时间,并给出一个链接,用以阅读历史页面,Show页面就很好,只要多接受一个版本参数就可以了。说到GridView,我们首先需要使用DbEntryDataSource,先在VisualWiki.Models里建立一个DataSources目录,然后创建ArticleHistoryDataSource:
namespace VisualWiki.Models.DataSources
{
    public class ArticleHistoryDataSource : DbEntryDataSource<ArticleHistory>
    {
    }
}

  然后在VisualWiki项目下创建History.aspx页面,修改其代码如下:
<%@ Page Title="" Language="C#" MasterPageFile="~/Main.master" %>

<script runat="server">
    [HttpParameter] public string title;
    
    protected void Page_Load(object sender, EventArgs e)
    {
        var article = Article.FindByTitle(title);
        if(article != null)
        {
            ArticleHistoryDataSource1.AddAndCondition(p => p.Article.Id == article.Id);
        }
        
        var hlf = (HyperLinkField) HistoryList.Columns[HistoryList.Columns.Count - 1];
        hlf.DataNavigateUrlFormatString = new UrlBuilder("~/Show.aspx").Add("title", title) + "&HistoryID={0}";
    }
</script>

<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
    <asp:GridView ID="HistoryList" runat="server" AllowPaging="True" 
        AutoGenerateColumns="False" BackColor="White" BorderColor="#E7E7FF" 
        BorderStyle="None" BorderWidth="1px" CellPadding="3" DataKeyNames="Id" 
        DataSourceID="ArticleHistoryDataSource1" GridLines="Horizontal" 
        EmptyDataText="Can't find any items.">
        <RowStyle BackColor="#E7E7FF" ForeColor="#4A3C8C" />
        <Columns>
            <asp:BoundField DataField="CreatedOn" HeaderText="Created On" 
                SortExpression="CreatedOn" />
            <asp:HyperLinkField Text="Show" DataNavigateUrlFields="Id" 
                DataNavigateUrlFormatString="~/Show.aspx?HistoryID={0}" >
            </asp:HyperLinkField>
        </Columns>
        <FooterStyle BackColor="#B5C7DE" ForeColor="#4A3C8C" />
        <PagerStyle BackColor="#E7E7FF" ForeColor="#4A3C8C" HorizontalAlign="Right" />
        <SelectedRowStyle BackColor="#738A9C" Font-Bold="True" ForeColor="#F7F7F7" />
        <HeaderStyle BackColor="#4A3C8C" Font-Bold="True" ForeColor="#F7F7F7" />
        <AlternatingRowStyle BackColor="#F7F7F7" />
    </asp:GridView>
    
    <biz:ArticleHistoryDataSource ID="ArticleHistoryDataSource1" runat="server" DefaultOrderBy="CreatedOn DESC, Id DESC" />
</asp:Content>

  运行程序,编辑Home页面几次,然后,将url里的Show修改为History,回车,就看到了我们的编辑历史了。当然,现在点击GridView里的Show链接,显示的仍然是最新的Wiki页面,所以,我们来修改一下Show.aspx,增加HistoryID参数:
<%@ Page Title="" Language="C#" MasterPageFile="~/Main.master" %>

<script runat="server">
    [HttpParameter(AllowEmpty = true)] public long? HistoryID;
    [HttpParameter] public string title;

    protected void Page_Load(object sender, EventArgs e)
    {
        if (HistoryID == null)
        {
            var article = Article.FindByTitle(title);
            ContextHolder.Text
                = article != null
                ? article.Content
                : "The wiki page does not exist.  The page will be created the first time you edit it. ";
        }
        else
        {
            var h = ArticleHistory.FindById(HistoryID.Value);
            if(h != null)
            {
                ContextHolder.Text = h.Content;
            }
        }
    }
</script>

<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
    <asp:Label ID="ContextHolder" runat="server" Text=""></asp:Label>
</asp:Content>

  现在,重新运行程序,确认Show页面已经可以按照HistoryID正确的显示历史数据。恩,总是修改url也不是办法,我们还是修改一下Main.master,加入Histroy链接吧:
<%@ Master Language="C#" Inherits="Lephone.Web.SmartMasterPageBase" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
    [HttpParameter] public string title;
    
    protected void Page_Load(object sender, EventArgs e)
    {
        var pageName = Request.Url.Segments[2].ToLower();
        if(pageName == "edit.aspx")
        {
            Edit.Enabled = false;
        }
        else
        {
            Edit.Enabled = true;
            Edit.NavigateUrl = new UrlBuilder("Edit.aspx").Add("title", title).ToString();
        }
        if(pageName == "history.aspx")
        {
            History.Enabled = false;
        }
        else
        {
            History.Enabled = true;
            History.NavigateUrl = new UrlBuilder("History.aspx").Add("title", title).ToString();
        }
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <asp:ContentPlaceHolder id="head" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:HyperLink ID="Edit" runat="server">Edit</asp:HyperLink> | 
        <asp:HyperLink ID="History" runat="server">History</asp:HyperLink>
        <br /><hr />
        <asp:ContentPlaceHolder id="ContentPlaceHolder1" runat="server">
        </asp:ContentPlaceHolder>
    </div>
    </form>
</body>
</html>

  咳咳,我们在写重复的代码了,看来需要小小的重构一下,不过在那之前,先把修改提交到SVN吧。目前的源代码可以在这里下载:VisualWiki3.7z

  未完待续……
2009-12-22 19:04:21 (阅读:241)
作者:梁利锋
标签:DotNet, DbEntry, Orm, VisualWiki