微型项目实践(9):页面的数据访问策略

简介:

上一篇中,我们完成了数据库的访问,今天我们来看看系统设计的最后一部分——UI层。加入了UI层之后,系统设计会变成这个样子:

system_design

这也就是系统最终的结构图。这个图上新添加的两个项目,一个是UI,一个是WebSite。其中前者依赖于业务逻辑和数据访问,提供统一的界面处理,而WebSite仅包含Aspx页面。需要注意的是,上图中箭头表示依赖或调用,而这个关系是具有传递性的,比如UI依赖于Business,而Business依赖于Common,则UI自然就依赖于Common。

将UI和WebSite分写在两个项目中,是我个人的一个习惯。其中UI主要包含页面基类和Helper类,还有数据库的获取方法,对于多种界面(比如既提供Web也提供WinForm)的系统,这一层次的抽象是必要的,而对于只提供Web访问的系统,把UI层放在WebSite中的App_Code文件夹下也无不可。

UI层中,目前就有两个核心类,一个是所有页面的基类,另一个是数据库生成类,其类结构图如下:

UI

其中DatabaseGateWay的作用就是读取Web.Config中数据库链接节点的连接字符串,并调用DataAccess层的方法,构造新的数据库:

   1:  namespace DongBlog.UI
   2:  {
   3:      /// <summary>
   4:      /// 数据库
   5:      /// </summary>
   6:      public class DatabaseGateWay
   7:      {
   8:          private const string DatabaseConnectionConfigurationName = 
"DongBlogDatabaseConnectionString";
   9:   
  10:          /// <summary>
  11:          /// 取得新的数据库
  12:          /// </summary>
  13:          /// <returns>新数据库</returns>
  14:          public static IDatabase GetNewDatabase()
  15:          {
  16:              return Database.New(ConfigurationManager
.ConnectionStrings[DatabaseGateWay.DatabaseConnectionConfigurationName]
.ConnectionString);
  17:          }
  18:      }
  19:  }

该类的GetNewDatabase()静态方法,是类型安全的,也是唯一使用到了DataAccess层具体实现的地方,系统的其它部分都只了解IDatabase而不了解其实现,更换不同的DataAccess只需要修改此方法。

PageBase类是所有Aspx页的基类,该类在该系统中只提供了数据库访问功能,即一个页面对应一个数据库访问,代码如下:

  11:  namespace DongBlog.UI
  12:  {
  13:      /// <summary>
  14:      /// 所有页面的基类
  15:      /// </summary>
  16:      public class PageBase : Page
  17:      {
  18:          private IDatabase _Database = DatabaseGateWay.GetNewDatabase();
  19:   
  20:          /// <summary>
  21:          /// 取得数据库访问
  22:          /// </summary>
  23:          protected IDatabase Database
  24:          {
  25:              get { return _Database; }
  26:          }
  27:      }
  28:  }

一个页面对应一个IDatabase,对于Linq来说,就是一个页面对应一个DataContext,这保证页面生存周期中的所有业务实体都来源或依附于同一个DataContext,避免了跨DataContext传递实体的问题。在Linq中,一个DataContext产生的Entity交由另一个DataContext中使用是一件非常麻烦的事情,必须保证实体必须使用Attach方法附加到新的DataContext上,如果不附加,则新的DataContext会认为该Entity是new出来的,这会导致再数据库中插入一条新的记录,而不是与现存记录建立关联,这个Bug很难调试,因为不会显示任何错误。我们举个例子说明这个问题。

我们经常会在用户登录的时候,在Session中储存登陆的用户:

User user = GetLoginUser(username, password);
if (user != null)
    Session["CurrentUser"] = user;
else
    Response.Redirect("Login.aspx");

这样以后我们就可以用Session["CurrentUser"]取得当前用户了。当用户新建一篇日志时,我们会使用类似下面的代码:

Blog blog = new Blog();
blog.Creator = Session["CurrentUser"] as User;
blog.Save(Database);

问题来了:上面两个代码通常来说不是发生在一个页面中,也就是说,从数据库中读取该user的DataContext早已不存在了,而新的、用于存储Blog的DataContext会认为这个blog相关的Creator是一个“新”的User,所以会在数据库中插入一条新的User记录,而不是和原来的User记录建立关联!为了避免这个情况,我们必须用Attach方法将Session["CurrentUser"]附加到新的DataContext中,上面的代码要这么改:

Database.Users.Attach(Session["CurrentUser"] as User);
Blog blog = new Blog();
blog.Creator = Session["CurrentUser"];
blog.Save(Database);

但是假设User还有关联的实体,比如Role、Power之类的东西,就需要全部附加上!否则就会插入新的关联记录!这几乎是不可能的,所以我们要保证每一个页面周期中所有的实体来源于同一个DataContext,对于上面这个例子,解决办法是不保存User,而保存UserID:

User user = GetLoginUser(username, password);
if (user != null)
    Session["CurrentUserID"] = user.ID;
else
    Response.Redirect("Login.aspx");

这样我们就可以在添加日志时这样写:

Blog blog = new Blog();
blog.Creator = Database.Users.GetByID(Convert.ToInt32(Session["CurrentUserID"]));
blog.Save(Database);

进一步,我们可以在PageBase中加载User,考虑在PageBase中存在以下代码:

private User _CurrentUser;
public User CurrentUser
{
    get
    {
        if(Session["CurrentUserID"] == null)
            return null;

        if(_CurrentUser == null)
            _CurrentUser = Database.Users.GetByID(Convert.ToInt32(Session["CurrentUserID"]));
        return _CurrentUser;
    }
}

这样我们就可以使用以下的代码建立日志了:

Blog blog = new Blog();
blog.Creator = CurrentUser;
blog.Save(Database);

关于PageBase的用处还有很多,包括但不限于以下这些:

  1. 构造Database。
  2. 构造当前User。
  3. 判断当前用户是否具有该页面的访问权限。
  4. 根据当前用户定制页面:加入不同的Css等。

另外,基于PageBase的扩展方法,将对所有页面有效,这点常常用于执行JavaScript。

下一篇中,我们开始编写我们第一个页面。

代码下载

本文转自冬冬博客园博客,原文链接:http://www.cnblogs.com/yuandong/archive/2008/05/17/1201508.html ,如需转载请自行联系原作者
相关文章
|
1月前
|
敏捷开发 开发框架 前端开发
构建高效移动应用:以用户为中心的设计策略
【4月更文挑战第3天】 在移动应用领域,"以用户为中心"并非一句空洞的口号,而是产品设计成功与否的关键。本文将探讨如何通过深入分析用户需求、优化用户界面(UI)和用户体验(UX),以及利用现代技术框架来构建既高效又引人入胜的移动应用。我们将剖析多个案例,提炼出可行的设计原则,并讨论如何在快速迭代的开发过程中维持设计的连贯性和功能性。通过这些策略,开发者可以创造出不仅满足用户需求,还能预见并塑造未来使用模式的移动应用。
160 0
|
7天前
|
存储 安全 Android开发
安卓应用开发:构建一个高效的用户登录系统
【5月更文挑战第3天】在移动应用开发中,用户登录系统的设计与实现是至关重要的一环。对于安卓平台而言,一个高效、安全且用户体验友好的登录系统能够显著提升应用的用户留存率和市场竞争力。本文将探讨在安卓平台上实现用户登录系统的最佳实践,包括对最新身份验证技术的应用、安全性考量以及性能优化策略。
|
11天前
|
监控 Java Android开发
安卓应用开发:打造高效用户界面的五大策略
【4月更文挑战第29天】 在安卓应用开发的世界中,构建一个既美观又高效的用户界面(UI)对于吸引和保留用户至关重要。本文将深入探讨五种策略,这些策略可以帮助开发者优化安卓应用的UI性能。我们将从布局优化讲起,逐步过渡到绘制优化、内存管理、异步处理以及最终的用户交互细节调整。通过这些实践技巧,你将能够为用户提供流畅而直观的体验,确保你的应用在竞争激烈的市场中脱颖而出。
|
16天前
|
数据库 Android开发 开发者
安卓应用开发:构建高效用户界面的策略
【4月更文挑战第24天】 在竞争激烈的移动应用市场中,一个流畅且响应迅速的用户界面(UI)是吸引和保留用户的关键。针对安卓平台,开发者面临着多样化的设备和系统版本,这增加了构建高效UI的复杂性。本文将深入分析安卓平台上构建高效用户界面的最佳实践,包括布局优化、资源管理和绘制性能的考量,旨在为开发者提供实用的技术指南,帮助他们创建更流畅的用户体验。
|
2月前
|
安全
什么是短剧系统开发/需求设计/逻辑方案/项目指南
The short drama system development plan refers to the development of a system for organizing and managing the process of short drama production, release, and playback.
|
7月前
|
消息中间件 存储 数据可视化
【结合业务需求给出合理的技术解决方案,改进现有模块功能,提高系统的可扩展性,封装性,稳定性】
【结合业务需求给出合理的技术解决方案,改进现有模块功能,提高系统的可扩展性,封装性,稳定性】
|
6月前
|
数据库
易搭工作流引擎用是什么开源 还是阿里自研产品,零代码平台场景页面映射数据库表是动态创建,采用什么框架处理,怎么让系统产生高并发能力。易搭权限有没有了解,求解。
易搭工作流引擎用是什么开源 还是阿里自研产品,零代码平台场景页面映射数据库表是动态创建,采用什么框架处理,怎么让系统产生高并发能力。易搭权限有没有了解,求解。
|
7月前
|
区块链
关于DEFI模式系统详细方案技术开发逻辑讲解方案
关于DEFI模式系统详细方案技术开发逻辑讲解方案
|
7月前
|
消息中间件 设计模式 缓存
聊聊结合业务需求给出合理的技术解决方案,改进现有模块功能,提高系统的可扩展性,封装性,稳定性
聊聊结合业务需求给出合理的技术解决方案,改进现有模块功能,提高系统的可扩展性,封装性,稳定性
|
11月前
|
架构师 中间件
架构日记 - 资源成本控制
架构日记 - 资源成本控制
50 0