通过分析蜘蛛侠论坛中的版块管理功能来介绍该如何使用我开发出来的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 > ()));
2 
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等大型成熟的框架相提并论,并且我还从未研究过他们的实现,呵呵。我只是希望通过自己的努力和积累,可以让我自己的开发很简单快捷而已。当然因为同时也希望能给大家分享我的成果,才发布给大家,并在这里写文章介绍这个东西。我觉得现在的我是多么的纯洁和可爱啊,应该说还没有被社会污染,哈哈。

 

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

 

你可能感兴趣的:(ROM)