通过分析蜘蛛侠论坛中的版块管理功能来介绍该如何使用我开发出来的ROM框架

 http://www.cnblogs.com/netfocus/archive/2010/01/10/1643207.html

 上面这个是框架发布页面的地址。

 

就以论坛版块管理模块作为例子来介绍这个框架吧,包括显示版块列表、新增版块、修改版块、删除版块四个功能;

1. 表设计:


SQL代码

1 CREATE TABLE [tb_Sections](
2     [EntityId] [int] IDENTITY(1,1) NOT NULL,
3     [Subject] [varchar](128) NOT NULL,
4     [Enabled] [int] NOT NULL,
5     [GroupId] [int] NOT NULL,
6     [TotalThreads] [int] NOT NULL
7 ) ON [PRIMARY]

 

2. ROM配置文件:

 1 <table name="tb_Sections">
 2     <field name="EntityId" type="int" typeEnum="Int" size="4" isIdentity="true" />
 3     <field name="Subject" type="varchar(128)" typeEnum="VarChar" size="128" />
 4     <field name="Enabled" type="int" typeEnum="Int" size="1" />
 5     <field name="GroupId" type="int" typeEnum="Int" size="4" />
 6     <field name="TotalThreads" type="int" typeEnum="Int" size="4" />
 7 </table>
 8 <entityMapping entityType="Forum.Business.Section, Forum.Business" tableName="tb_Sections">
 9     <propertyNode propertyName="EntityId" fieldName="EntityId" />
10     <propertyNode propertyName="Subject" fieldName="Subject" />
11     <propertyNode propertyName="Enabled" fieldName="Enabled" />
12     <propertyNode propertyName="GroupId" fieldName="GroupId" />
13     <propertyNode propertyName="TotalThreads" fieldName="TotalThreads" />
14 </entityMapping>

说明:table结点表示tb_Sections表的结构;entityMapping结点表示Section对象和tb_Sections表的对应关系;

 

需要特别说明的是,对象可以嵌套并和表或视图的字段对应;例如下面这个例子:

 1 <entityMapping entityType="System.Web.Core.UserAndRole, System.Web.Core" tableName="vw_RoleUsers">
 2     <propertyNode propertyName="EntityId" fieldName="EntityId" />
 3     <propertyNode propertyName="User">
 4         <propertyNode propertyName="EntityId" fieldName="UserId" />
 5         <propertyNode propertyName="MemberId" fieldName="MemberId" />
 6         <propertyNode propertyName="NickName" fieldName="NickName" />
 7         <propertyNode propertyName="Email" fieldName="Email" />
 8         <propertyNode propertyName="AvatarFileName" fieldName="AvatarFileName" />
 9         <propertyNode propertyName="AvatarContent" fieldName="AvatarContent" />
10         <propertyNode propertyName="UserStatus" fieldName="UserStatus" />
11         <propertyNode propertyName="TotalMarks" fieldName="TotalMarks" />
12     </propertyNode>
13     <propertyNode propertyName="Role">
14         <propertyNode propertyName="EntityId" fieldName="RoleId" />
15         <propertyNode propertyName="Name" fieldName="RoleName" />
16         <propertyNode propertyName="Description" fieldName="RoleDescription" />
17         <propertyNode propertyName="RoleType" fieldName="RoleType" />
18     </propertyNode>
19 </entityMapping>

 

UserAndRole对象中包含了一个User对象和一个Role对象,UserAndRole对象和一个视图vw_RoleUsers对应;其中User对象中的一些属性和视图中的相关字段对应,Role对象也是一样;

 

3. 功能实现:

3.1 显示版块列表、删除版块功能的实现:

  1 public class SectionList : ForumUserControl
  2 {
  3     protected Repeater list;
  4     protected ValuedDropDownList groupDropDownList;
  5     protected AjaxPager pager;
  6     protected CurrentPage currentPage;
  7 
  8     public string AdminUserRoleId
  9     {
 10         get
 11         {
 12             string s = ViewState["AdminUserRoleId"] as string;
 13             if (s == null)
 14             {
 15                 s = string.Empty;
 16             }
 17             return s;
 18         }
 19         set
 20         {
 21             ViewState["AdminUserRoleId"] = value;
 22         }
 23     }
 24 
 25     protected override void OnFirstLoad()
 26     {
 27         if (!ValidatePermission(PermissionType.SectionAdmin))
 28         {
 29             throw new Exception("您没有管理版块或版块组的权限!");
 30         }
 31     }
 32     public override void GetRequests(List<RequestBinder> requestBinders)
 33     {
 34         requestBinders.Add(BinderBuilder.BuildGetAllBinder(this, new TRequest<Group>()));
 35 
 36         TRequest<Section> request = new TRequest<Section>();
 37         request.PageSize = pager.PageSize;
 38         requestBinders.Add(BinderBuilder.BuildGetListBinder(this, request));
 39     }
 40     public override void GetReplies(List<RequestBinder> requestBinders)
 41     {
 42         BindGroupDropDownList(requestBinders[0].Reply.EntityList);
 43         BindRepeater(requestBinders[1].Reply);
 44         BindPager(requestBinders[1].Reply.TotalRecords, 1);
 45     }
 46 
 47     #region Ajax Methods
 48 
 49     [AjaxMethod]
 50     public void DeleteSection(int sectionId)
 51     {
 52         TRequest<Post> postRequest = new TRequest<Post>();
 53         postRequest.Data.SectionId.Value = sectionId;
 54 
 55         ThreadRequest threadRequest = new ThreadRequest();
 56         threadRequest.Data.SectionId.Value = sectionId;
 57 
 58         TRequest<SectionRoleUser> sectionRoleUserRequest = new TRequest<SectionRoleUser>();
 59         sectionRoleUserRequest.Data.SectionId.Value = sectionId;
 60 
 61         ProcessResult result = Engine.Executes(BinderBuilder.BuildDeleteListBinder(postRequest), BinderBuilder.BuildDeleteListBinder(threadRequest), BinderBuilder.BuildDeleteListBinder(sectionRoleUserRequest), BinderBuilder.BuildDeleteBinder<Section>(sectionId));
 62         if (!result.IsSuccess)
 63         {
 64             throw new Exception(result.ErrorMessage);
 65         }
 66     }
 67     [AjaxMethod]
 68     public void DeleteSections(string items)
 69     {
 70         if (string.IsNullOrEmpty(items))
 71         {
 72             return;
 73         }
 74         int entityId = 0;
 75         foreach (string item in items.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries))
 76         {
 77             entityId = Globals.ChangeType<int>(item);
 78             if (entityId > 0)
 79             {
 80                 DeleteSection(entityId);
 81             }
 82         }
 83     }
 84     [AjaxMethod]
 85     public ListManageAjaxData RefreshList(int groupId, int pageIndex)
 86     {
 87         TRequest<Section> request = new TRequest<Section>();
 88 
 89         request.Data.GroupId.Value = groupId;
 90         request.PageIndex = pageIndex;
 91         request.PageSize = pager.PageSize;
 92 
 93         Reply reply = Engine.GetEntityList(request);
 94 
 95         BindRepeater(reply);
 96         BindPager(reply.TotalRecords, pageIndex);
 97 
 98         ListManageAjaxData result = new ListManageAjaxData();
 99         result.ListContent = Globals.RenderControl(list);
100         result.PagingContent = Globals.RenderControl(currentPage) + Globals.RenderControl(pager);
101 
102         return result;
103     }
104 
105     #endregion
106 
107     #region Private Methods
108 
109     private void BindGroupDropDownList(EntityList groups)
110     {
111         Group topGroup = new Group();
112         topGroup.Subject.Value = "所有版块组";
113         groups.Insert(0, topGroup);
114 
115         groupDropDownList.DataSource = groups;
116         groupDropDownList.DataTextField = "Subject";
117         groupDropDownList.DataValueField = "EntityId";
118         groupDropDownList.DataBind();
119     }
120     private void BindRepeater(Reply reply)
121     {
122         AdminUserRoleId = RoleManager.GetRole(ForumConfiguration.Instance.ForumSectionAdminRoleName).EntityId.Value.ToString();
123         list.DataSource = reply.EntityList;
124         list.DataBind();
125     }
126     private void BindPager(int totalRecords, int pageIndex)
127     {
128         if (pager != null)
129         {
130             pager.TotalRecords = totalRecords;
131             pager.PageIndex = pageIndex;
132             if (currentPage != null)
133             {
134                 currentPage.TotalRecords = pager.TotalRecords;
135                 currentPage.TotalPages = pager.TotalPages;
136                 currentPage.PageIndex = pager.PageIndex;
137             }
138         }
139     }
140 
141     #endregion
142 }

 

说明:

OnFirstLoad函数在前页面第一次显示时被调用,我在该函数中进行了权限的判断:

1 protected override void OnFirstLoad()
2 {
3     if (!ValidatePermission(PermissionType.SectionAdmin))
4     {
5         throw new Exception("您没有管理版块或版块组的权限!");
6     }
7 }

 

 

在基类控件中规定如下的时候才会调用该方法:

1 protected override void OnLoad(EventArgs e)
2 {
3     if (!Page.IsPostBack && !Page.IsCallback && !AjaxManager.IsCallBack)
4     {
5         OnFirstLoad();
6     }
7 }

 

 

重写GetRequests函数使得各个具体控件有机会告诉框架当前的Url请求需要发送什么数据请求。GetRequests函数由框架负责调用,在这个例子中,创建了两个请求并添加到集合中:

1 requestBinders.Add(BinderBuilder.BuildGetAllBinder(this, new TRequest<Group>()));

3 TRequest<Section> request = new TRequest<Section>();
4 request.PageSize = pager.PageSize;
5 requestBinders.Add(BinderBuilder.BuildGetListBinder(this, request));

 

其中第一个请求目的是获取所有的版块分组,第二个请求目的是为了获取当前页下的所有版块信息;BuildGetAllBinder方法告诉框架我不需要分页获取数据,而是获取这类数据的全部记录;

BuildGetListBinder告诉框架应该获取当前PageIndex下的PageSize条记录;

 

另外,我们还重写了GetReplies方法,该方法由框架调用。当框架获取了所请求的数据后,会调用该方法,将请求的回复返回给请求者。在该方法中,我们可以对返回的数据进行处理,如绑定到Repeater控件和设置分页控件信息等。

1 public override void GetReplies(List<RequestBinder> requestBinders)
2 {
3     BindGroupDropDownList(requestBinders[0].Reply.EntityList);
4     BindRepeater(requestBinders[1].Reply);
5     BindPager(requestBinders[1].Reply.TotalRecords, 1);
6 }

 

其中requestBinders[0]表示第一个请求的回复,requestBinders[1]表示第二个请求的回复;BindGroupDropDownList、BinderRepeater、BindPager三个函数分别用来将返回的数据绑定到控件;

 

通过GetRequests、以及GetReplies这两个函数,我们可以不必自己去关心该在什么时候去获取数据,而只要告诉框架我要获取什么数据即可;这样做的好处是,比如当前页面有10个用户控件,每个用户控件都需要获取自己所需要的数据,我们以往的做法是,每个控件自己去建立数据库连接并自己负责去获取数据并处理数据。这样做带来的后果是一次页面显示时,可能需要建立10次数据库连接,这样会影响性能;而如果基于我这样的设计,10个用户控件自己并不负责去建立数据库连接,而只是简单的告诉框架我要获取什么数据,框架会负责搜集搜索当前请求所需要的所有数据库请求,并一次性执行,并且只需要建立一次数据库连接即可。等所有请求处理完之后,再统一将所有的回复发给相应的控件。

 

删除版块功能的实现,通过Ajax技术实现,代码如下:

 1 [AjaxMethod]
 2 public void DeleteSection(int sectionId)
 3 {
 4     TRequest<Post> postRequest = new TRequest<Post>();
 5     postRequest.Data.SectionId.Value = sectionId;
 6 
 7     ThreadRequest threadRequest = new ThreadRequest();
 8     threadRequest.Data.SectionId.Value = sectionId;
 9 
10     TRequest<SectionRoleUser> sectionRoleUserRequest = new TRequest<SectionRoleUser>();
11     sectionRoleUserRequest.Data.SectionId.Value = sectionId;
12 
13     ProcessResult result = Engine.Executes(
14         BinderBuilder.BuildDeleteListBinder(postRequest),
15         BinderBuilder.BuildDeleteListBinder(threadRequest),
16         BinderBuilder.BuildDeleteListBinder(sectionRoleUserRequest),
17         BinderBuilder.BuildDeleteBinder<Section>(sectionId));
18 
19     if (!result.IsSuccess)
20     {
21         throw new Exception(result.ErrorMessage);
22     }
23 }

 

该函数接受一个由Ajax框架传递过来的一个sectionId。首先交代一下一个论坛中一些基本表的关系:一个版块下包含多个帖子,一个帖子包含多个回复,另外一个版块还会有一些版主;

所以当我要删除一个版块时,还必须级联删除所有与之相关的帖子、回复、版主信息;而所有这些删除操作必须以事务的方式来执行,这样才可以确保数据完整性。

所以,上面的函数中我创建了四个请求,并全部传递给数据处理引擎Engine的Executes方法,该方法可以接受多个请求,并以事务的方式执行所有的请求;

BuildDeleteListBinder表示我要创建一个请求,该请求会删除符合指定条件下的所有记录;BuildDeleteBinder表示我要创建一个请求,该请求会根据一个主键删除一个实体,而实体的类型由泛型类型来告诉框架;

 

3.2 新增版块:

为了简单起见,我直接介绍新增版块的相关代码,而不写在前面已经介绍过的代码了。

 1 [AjaxMethod(IncludeControlValuesWithCallBack = true)]
 2 public void Save()
 3 {
 4     CheckData();
 5 
 6     Section section = new Section();
 7     section.Subject.Value = subjectTextBox.Value;
 8     section.Enabled.Value = enabledCheckBox.Checked ? 1 : 0;
 9     section.GroupId.Value = int.Parse(groupDropDownList.Value);
10     Engine.Create(section);
11 }
12 
13 private void CheckData()
14 {
15     if (string.IsNullOrEmpty(groupDropDownList.Value))
16     {
17         throw new Exception("请选择一个版块组!");
18     }
19 
20     TRequest<Section> request = new TRequest<Section>();
21     request.Data.Subject.Value = subjectTextBox.Value.Trim();
22     if (Engine.GetAll(request).Count > 0)
23     {
24         throw new Exception("您要添加的版块已经存在!");
25     }
26 }

 

在添加版块时,需要检查名称是否重复,在CheckData函数中,通过调用Engine提供的GetAll方法来获取所有当前版块名称的记录,如果有,说明存在重复;如果不存在,则做保存操作。

可以清晰的看到,我先创建一个版块对象,然后调用Engine.Create方法完成版块的创建。

 

3.3 修改版块:

 1 [AjaxMethod(IncludeControlValuesWithCallBack = true)]
 2 public void Save()
 3 {
 4     Section section = Engine.Get<Section>(new TRequest<Section>(GetValue<int>(ForumParameterName.SectionId)));
 5 
 6     CheckData(section);
 7 
 8     section.Enabled.Value = enabledCheckBox.Checked ? 1 : 0;
 9     section.Subject.Value = subjectTextBox.Value;
10     Engine.Update(section);
11 }
12 private void CheckData(Section section)
13 {
14     if (section == null)
15     {
16         throw new Exception("版块组已经被删除!");
17     }
18     TRequest<Section> request = new TRequest<Section>();
19     request.Data.Subject.Value = subjectTextBox.Value.Trim();
20     EntityList sections = Engine.GetAll(request);
21     if (sections.Count > 0 && ((Section)sections[0]).EntityId.Value != section.EntityId.Value)
22     {
23         throw new Exception("新版块名称和已有的版块名称重复!");
24     }
25 }

 

在保存修改的版块时,首先通过Engine.Get<TEntity>方法获取当前正在编辑的版块,然后同样先检查版块名称是否合法,如果合法,

则调用Engine.Update方法保存版块;一切看起来都非常简单。

 

总结:

本文通过介绍一个论坛中版块的管理来简单介绍该如何使用我的框架所提供的实用功能。基于我提供的框架,当我们以后要开发一个应用模块时,只要先创建好表,然后做几个非常简单的ROM配置,然后就可以调用框架提供的接口来完成你想要的数据处理请求了。而你的所有数据处理请求都是创建Request,然后发送给框架,然后框架就会返回给你一个Reply,或者直接返回你想要的数据。也就是说,你以后都不必再写SQL了,也不需要写自己的数据访问层了。当然,现在很多ROM框架也都已经提供了非常强大的功能,让我们在开发应用时,可以不必去面向数据库字段,而是直接面向对象的属性。我开发这个ROM框架,也是希望能够提供给大家另外一种ROM的选择。当然我自知自己的这个东西还远不能和Hibernate,EF等大型成熟的框架相提并论,并且我还从未研究过他们的实现,呵呵。我只是希望通过自己的努力和积累,可以让我自己的开发很简单快捷而已。当然因为同时也希望能给大家分享我的成果,才发布给大家,并在这里写文章介绍这个东西。我觉得现在的我是多么的纯洁和可爱啊,应该说还没有被社会污染,哈哈。

 

好了,就这么多吧!这个框架的其他内容,如果大家有兴趣,就自行去研究吧,基本上所有的功能在我发布的蜘蛛侠论坛中都已经用到了。

时间: 2024-09-17 03:47:09

通过分析蜘蛛侠论坛中的版块管理功能来介绍该如何使用我开发出来的ROM框架的相关文章

Visual paradigm中的需求管理功能

需求的产生可能来自一些文件的描述,也可能是通过访谈或者观察等方式取得(Karl E. Wiegers的<<软件需求>>).Visual Paradigm提供一些工具来对需求进行分析.   第一,从某个文件中产生需求或以文档形式记录需求. 如果有一个文档,对系统需求进行简单的描述.可以将其重要的文字部导入进行分析,这就是Textual Analysis. 导入文字后,使用Highlight工具,选中可能是产生需求的文字,在下方,程序会列出这些待选项.右击这些项目,可以生成到Requi

如何实现论坛中的远程附件功能

背景 网站远程附件功能是指将用户上传的附件直接存储到远端的存储服务器,一般是通过FTP的方式存储到远程的FTP服务器.目前Discuz论坛.phpwind论坛.Wordpress个人网站等都支持远程附件功能. 将附件远程存储到oss后,用户访问附件时将直接从oss下载,一方面可以减少网站的流量,同时附件本身的可用性也将提高. 一.下载并运行OSS FTP OSS FTP工具是一个特殊FTP server, 它接收普通FTP请求后,将对文件.文件夹的操作映射为对OSS的操作,从而使得您可以基于FT

Linux系统中的进程管理工具SystemD介绍

  SystemD是Linux下的一种init软件,由Lennart Poettering带头开发,并在LGPL 2.1及其后续版本许可证下开源发布.Lennart是redhat员工,但SystemD不是redhat项目.其开发目标是提供更优秀的框架以表示系统服务间的依赖关系,并依此实现系统初始化时服务的并行启动,同时达到降低Shell的系统开销的效果,最终代替现在常用的System V与BSD风格init程序. SystemD这一名字源于Unix中的一个惯例:在Unix中常以"d"作

分析Android App中内置换肤功能的实现方式_Android

Android平台api没有特意为换肤提供一套简便的机制,这可能是外国的软件更注重功能和易用,不流行换肤.系统不提供直接支持,只能自行研究. 换肤,可以认为是动态替换资源(文字.颜色.字体大小.图片.布局文件--).这个使用编程语言来动态设置是可以做到的,例如使用View的setBackgroundResource.setTextSize.setTextColor等函数.但我们不可能在每个activity里对页面里的所有控件都通过调用这些函数来换肤,这样的程序代码难以维护.扩展,也违背了UI和代

分析Android App中内置换肤功能的实现方式

Android平台api没有特意为换肤提供一套简便的机制,这可能是外国的软件更注重功能和易用,不流行换肤.系统不提供直接支持,只能自行研究. 换肤,可以认为是动态替换资源(文字.颜色.字体大小.图片.布局文件--).这个使用编程语言来动态设置是可以做到的,例如使用View的setBackgroundResource.setTextSize.setTextColor等函数.但我们不可能在每个activity里对页面里的所有控件都通过调用这些函数来换肤,这样的程序代码难以维护.扩展,也违背了UI和代

WinXP系统下中关于网桥个别功能的介绍

  注意事项:大家在配置Windows XP的网桥时要注意以下几点: 1.配置Windows XP的网桥服务器时不用配制成域控制器,只要配置成为独立的服务器即可. 2.保证所安装的网卡都能正常工作,其中作为网桥服务器的计算机拥有两块网卡. 3.Windows XP网桥所支持的网络通信协议是TCP/ip,只能在以TCP/IP协议为基础的网络中转发数据包.如果计算机使用的是linux或其他操作系统,只要正确装载了TCP/IP协议,Windows XP网桥一样可以与它协同工作. A.给作为网桥的计算机

中华通短信功能使用介绍

  点击软件"收发短信"的按扭,输入对方的电话号码,编辑短信内容点击"发送"对方就可以收到.(目前短信功能只支持发送国内移动.联通号码,不支持发送国际短信及小灵通号码,余额低于1元是不能使用短信服务的) 以下是短信收发的动画演示图,用户发送短信后可在"已发短信"栏查看已发送信息,也在"已收短信"里查看接收短信的记录: 使用短信功能的同时,请用户自觉遵守短信发送规定,请勿发送违规短信. 详细的短信发送细则请参考:http://w

蜘蛛侠论坛核心框架分析1 - 如何设计与实现当前访问用户

论坛演示地址:http://www.entityspider.com/  源代码下载地址:http://files.cnblogs.com/netfocus/Forum.rar   蜘蛛侠论坛采用Forms验证方式.   1: 当用户输入用户名和密码并登陆, 此时, 我们会将当前用户的身份标识保存到客户端: 文件: \Core\Managers\MemberManager.cs 代码: CookieManager.AddCookieToResponse( FormsAuthentication.

C++中的内存管理

在C++中也是少不了对内存的管理,在C++中只要有new的地方,在写代码的时候都要想着delete. new分配的时堆内存,在函数结束的时候不会自动释放,如果不delete我分配的堆内存,则会造成内存泄露.所以我们要学会内存管理,不要内存泄露.在C++中的内存管理机制和OC中的还不太一样,在OC中的ARC机制会给程序员的内存管理省不少事,但在C++中没有ARC所以我们要自己管理好自己开辟的内存.Java中也有自己相应的内存管理机制,比如JDBC里的获取的各种资源在finally里进行close等