(原创)Asp.net使按第三范式设计的数据库大放异彩

1 篇文章 0 订阅

第三范式的要求是表中的非主键列必须跟主键列存在依赖,如果非主键列间存在依赖那就不符合3NF,比如我们常见的冗余就不符合。有人都觉得3NF不太符合实际需求,所以数据库设计上都遵循了2NF设计,但我觉得按3NF设计的表其实非常简洁明了,层次结构清晰,只是平常遇到的一表能解决问题需要分解到多个表,原因就是3NF的要求很柯刻。

下面我们看一下例子中要使用的按3NF设计的表(例子表使用SQLSERVER 2005制作):


按照这种设计方法,估计字典表要成百上千都有可能,那且不是要命?不急,我们稍作修改就即可:


现在又产生了一个重要的问题,什么问题呢,就是查询的时候得有多少关联SQL需要写啊,查询慢,SQL语句笨重,如果有冗余字段就不需要有这些烦琐的关联了。

不急,这些问题不需要SQLSERVER来处理,交给asp.net来做就好了。下面先讲实现,然后再说核心的解决方式。

我最近为东家编写了一个控件,命名为RSGrid,使用它即可解决问题,不过他需要依赖配置,我使用了表结构作为配置源。先看效果图:


根据上面的效果,我们需要作一翻配置:



实际查询和分页的存储过程:

USE [HisTest]
GO
/****** 对象:  StoredProcedure [dbo].[sp_test]    脚本日期: 08/21/2012 11:41:37 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO


/*
 * 描述:转诊系统自定义控件的测试过程。
 * 参数:@BussionID 交易号
         @pageIndex 页索引
		 @pageNumber 每页记录数
 * 创建人:罗毅
 * 创建日期:2012.08.15
 * 测试:exec sp_test 1,1,20,''
*/
CREATE PROCEDURE [dbo].[sp_test](@BussionID int,@pageIndex int,@pageNumber int,@where varchar(100))
as
begin
	if @BussionID = 1 
    begin
		DECLARE @ID INT
        --如果在第一页,则先定位到第一条记录,另外定位到本页第一条记录
		DECLARE @v INT
		SET @v = (@pageIndex-1)*@pageNumber + 1
		SET ROWCOUNT @v
		SELECT @ID=YGBH FROM YuanGong ORDER BY YGBH
		SET ROWCOUNT @pageNumber
		SELECT * FROM YuanGong WHERE YGBH>=@ID ORDER BY YGBH
		SET ROWCOUNT 0
    end
	IF @BussionID = 2
	BEGIN
		--统计总记录数和总页数
		DECLARE @PageCount INT
		DECLARE @RecordCount INT
		SELECT @RecordCount = COUNT(*) FROM YuanGong
		SET @PageCount = @RecordCount / @pageNumber
		IF @RecordCount % @pageNumber >0
		BEGIN
			SET @PageCount = @PageCount + 1
		END
        
		SELECT @PageCount AS PageCount,@RecordCount AS RecordCount
	END
end



经过一系列的数据配置以及进行数据查询的存在过程,那后面的工作就交给asp.net了。

首先引入RSGrid.DLL,并在Default.aspx中加入RSGrid控件,

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.SqlClient;

namespace WebApplication1
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                RSGrid.GridColumnDictionary gcd = new RSGrid.GridColumnDictionary();
                //清除缓存
                gcd.RemoveAllDictionary();
                //缓存字典表。这里可以写在程序启动的地方,只需要缓存一次。
                DataSet ds = GetDataSet("select A.DLBM AS ItemCode,A.DLMC AS ItemCode,B.XLBM AS SubItemCode,B.XLMC AS SubItemName from ZiDian1 A,ZiDian2 B where A.DLBM=B.DLBM ORDER BY A.DLBM,B.XLBM");
                gcd.BingDictionary(ds);
                ds.Dispose();
            }
        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            Int32 pageIndex = RSGrid1.PageIndex;
            Click(pageIndex);
        }

        private void Click(int pageIndex)
        {
            Int32 pageNumber = RSGrid1.PageNumber;
            RSGrid1.PageIndex = pageIndex;
            string formatSql = "exec sp_test {0},{1},{2}, ''";
            string sql = string.Format(formatSql, 2, 1, pageNumber);
            //获取总页数、总记录数
            using (DataSet ds = GetDataSet(sql))
            {
                RSGrid1.PageCount = Int32.Parse(ds.Tables[0].Rows[0]["PageCount"].ToString());
                RSGrid1.RecordCount = Int32.Parse(ds.Tables[0].Rows[0]["RecordCount"].ToString());
            }
            //获取列配置
            RSGrid1.ColumnsSettingSource = GetDataSet("SELECT * FROM SYS_Columns");
            //获取数据
            sql = string.Format(formatSql, 1, pageIndex, pageNumber);
            RSGrid1.DataSource = GetDataSet(sql);
            RSGrid1.Bind();
        }

        private DataSet GetDataSet(string sql)
        {
            string connStr = System.Configuration.ConfigurationManager.ConnectionStrings["SQLConnString"].ToString();
            SqlConnection conn = new SqlConnection(connStr);
            SqlCommand cmd = new SqlCommand(sql, conn);
            SqlDataAdapter da = new SqlDataAdapter(cmd);
            DataSet ds = new DataSet();
            da.Fill(ds);
            conn.Close();
            cmd.Dispose();
            return ds;
        }

		//首页
        protected void RSGrid1_OnFirstPageClick(object sender, ImageClickEventArgs e)
        {
            Click(1);
        }
		//上一页
        protected void RSGrid1_OnPrevPageClick(object sender, ImageClickEventArgs e)
        {
            Int32 pageIndex = RSGrid1.PageIndex;
            if (pageIndex > 1)
                Click(pageIndex-1);
        }
		//下一页
        protected void RSGrid1_OnNextPageClick(object sender, ImageClickEventArgs e)
        {
            Int32 pageIndex = RSGrid1.PageIndex;

            if (pageIndex < RSGrid1.PageCount)
                Click(pageIndex+1);
            else
            {
                Click(pageIndex);
            }
        }
		//末页
        protected void RSGrid1_OnLastPageClick(object sender, ImageClickEventArgs e)
        {
            Int32 pageIndex = RSGrid1.PageCount;
            Click(pageIndex);
        }
		//响应自定义的命令		
        protected void RSGrid1_CommandEvent(object sender, CommandEventArgs e)
        {
            if (e.CommandName.Equals("Del"))
            {
                Button1.Text = e.CommandArgument.ToString();
            }
            if (e.CommandName.Equals("View"))
            {
                Label1.Text = e.CommandArgument.ToString();
            }
        }
    }
}

如果是射映成图片,比如“性别”字段需要使用图片来展示,那需要修改配置:



最终展示结果:


OK,现在已经是大功告成了,跑起来看看吧。大笑

主要是使用了asp.net的cache,让每次的查询都100%命中字典缓存,服务器的映射工作都放到应用服务器上,这样服务器只需要关系业务表间的关联逻辑就行了,所以,在RSGrid的支持下,大胆地使用3NF来设计数据库吧,查询开销和查询速度绝对优于冗余设计的表。

欢迎大家拍砖,如果有跟我雷同的想法和控件,请大家也告诉我一下,我也学习学习。

控件已上传到我的资源中。http://download.csdn.net/detail/lllllllllluoyi/4515054



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值