`
ideage
  • 浏览: 326173 次
社区版块
存档分类
最新评论

数据访问层和SQLWrapper库(sql包装器) 转载

阅读更多

转载 http://www.codeproject.com/cs/database/SqlWrapper.asp
源代码本地下载: 
使用SQLWrapper库,你可以写非常少的代码来创建你的数据访问类.

简介
你曾经在你的项目中创建数据访问层吗?你很可能创建了一个类或者一些类,他们包含几个方法,调用了存储过程或者执行一个SQL语句.如果数据库包含很多表,这是个很烦人的工作过程.最糟糕的是,这个方法要很多的同样的步骤(创建一个命令对象,填充它的属性,执行,然后返回结果).并且很少包含其他的逻辑.你有两个方法:手工写这些代码,或者(自动)生成他们.这两个方法,你会有很多源代码.

以前我在用这两个方法时,我就感觉在哪里有更容易的方法.AutoSprocTool给我一个开发SqlWrapper库的想法.

一个简单的例子
让我们写两个类,他们和Northwind数据库一起工作.一个类Orders1使用通常的方法.
差异是显而易见的.Orders2 包含了很少的代码但是他们使用起来差不多相同,仅仅是创建的方法不同.

public class Orders1
{
    
private SqlConnection m_connection = null;

    
public SqlConnection Connection
    
{
        
get{return m_connection;}
        
set{m_connection = value;}
    }


    
public DataSet CustOrdersDetail(int OrderID)
    
{
        SqlCommand cmd 
= new SqlCommand("CustOrdersDetail", m_connection);
        cmd.CommandType 
= CommandType.StoredProcedure;
        cmd.Parameters.Add(
"@OrderID", SqlDbType.Int);
        cmd.Parameters[
"@OrderID"].Value = OrderID;
        SqlDataAdapter da 
= new SqlDataAdapter(cmd);
        DataSet ds 
= new DataSet();
        da.Fill(ds);
        
return ds;
    }


    
public int CountByEmployee(int EmployeeID)
    
{
        SqlCommand cmd 
= new SqlCommand(
            
"select count(*) from Orders where EmployeeID=@EmployeeID"
            m_connection);
        cmd.CommandType 
= CommandType.Text;
        cmd.Parameters.Add(
"@EmployeeID", SqlDbType.Int);
        cmd.Parameters[
"@EmployeeID"].Value = EmployeeID;
        
int count = (int)cmd.ExecuteScalar();
        
return count;
    }

    
}


另一个使用SqlWrapper,
public abstract class Orders2 : SqlWrapperBase
{
    
public abstract DataSet CustOrdersDetail(int OrderID);

    [SWCommand(
"select count(*) from Orders where EmployeeID=@EmployeeID")]
    
public abstract int CountByEmployee(int EmployeeID);
}


现在让我们看看如何使用这些类.
SqlConnection cnn 
= new SqlConnection(
    ConfigurationSettings.AppSettings[
"ConnectionString"]);
cnn.Open();

// working with the ordinary class
Orders1 orders1 = new Orders1();
orders1.Connection 
= cnn;
DataSet ds1 
= orders1.CustOrdersDetail(10248);
int count1 = orders1.CountByEmployee(6);

// working with the wrapped class
Orders2 orders2 = (Orders2)WrapFactory.Create(typeof(Orders2));
orders2.Connection 
= cnn;
DataSet ds2 
= orders2.CustOrdersDetail(10248);
int count2 = orders2.CountByEmployee(6);

 

SqlWarpper如何工作
为了创建一个包装类,你要从SqlWrapperBase继承,并且定义抽象方法,使用自定义属性定义要执行什么,如何获得和获得什么结果.如果没有指定方法属性,那么方法的名称将被用做存储过程名称.你也可以定义任意数量的具体方法,如果你要在执行sql语句之外,还有一些更多的逻辑.然后,你可以通过调用WrapFactory.Create()方法,创建定义类的一个对象.这个方法使用System.Reflection.Emit 命名空间的类,为抽象方法添加执行.例如,下面的方法:

[SWCommand("select count(*) from Orders where EmployeeID=@EmployeeID")]
public abstract int CountByEmployee(int EmployeeID);

将被执行为:
[SWCommand(
"select count(*) from Orders where EmployeeID=@EmployeeID")]
public int CountByEmployee(int EmployeeID)
{
    MethodInfo method 
= (MethodInfo)MethodBase.GetCurrentMethod();
    
object[] values = new object[1];
    values[
0= EmployeeID;
    
object obj = SWExecutor.ExecuteMethodAndGetResult(
            m_connection, 
            m_transaction, 
            method, 
            values, 
            m_autoCloseConnection);

    
return (int)obj;
}


SWExecutor.ExecuteMethodAndGetResult() 方法执行了主要的工作.它创建了SqlCommand和返回了执行的结果. 为了这个用途,变量method提供了下面的信息:
command text (命令)
command type (命令类型)
execution method (执行的方法名称)
parameter names (参数名称)
parameter data types (参数类型)
parameter directions (参数方向)
parameter sizes, scales and precisions (参数的大小,范围,精度)
behavior in case null or DBNull is returned instead of a scalar value
如果没有返回一个精度值,而是返回了空或者DBNull时的行为.
behavior in case DBNull value must be passed to a parameter
如果必须传递一个空值作为参数时的行为.
所有的这些信息都将通过方法签名提供,其他可选的通过方法属性和参数属性.

下面的图显示了SqlWrapper类直接的联系
 


SqlWrapperBase

SqlWrapperBase类是所有的包装类的基本类,它包含了下面的属性:
Connection 属性
Transaction 属性
AutoCloseConnection 属性.如果为真,那么连接在每次的命令执行完毕就会自动关闭.
你可以在你的包装类中使用上面的属性,因为他们是protected.

SWCommandAttribute

这是一个可选的方法属性,包含了下面的属性.

CommandType可以是下面的值:SWCommandType.Text,SWCommandType.StoreProcedure和SWCommandType.InsertUpdate.这几个值类似于System.Data.CommandType枚举的值. SWCommandType.InsertUpdate 将在以后讲述.默认值是SWCommandType.Text.
CommandText 包含了一个命令文本.这依赖于CommandType属性值.
ReturnIfNull包含了一个值,如果执行了一个命令返回了空,那么将返回此值.
MissingSchemaAction是一个值,SqlDataAdapter.MissingShemaAction.默认是Add.

除了CommandText属性以外都是可选的属性.

重要:如果这个属性省略了,那么方法名称将被用做CommandText属性,CommandType属性将等于SWCommandTYpe.StoreProcedure.

SWParameterAttribute

这是一个可选的参数属性,包含下列属性:
Name:包含了参数名称,如果省略,使用方法参数名称
SqlDbType,包含了值的类型,对应了SqlParameter.SqlDbType属性.
Size 包含了命令参数的大小,对应了SqlParameter.Size属性.
Precision 包含了参数的精度.对应了SqlParameter.Presision
Scale 包含了参数的小数位数.对应了SqlParameter.Scale.
TreatAsNull 包含了被翻译成DBNull的值.在数字参数时很有用.
ParameterType 包含了下列值:SWParameterType.Default, SWParameterType.SPReturnValue, SWParameterType.Key 和 SWParameterType.Identity.默认值是SWParameterType.Default.

所有的属性都是可选的.
当ParameterType属性值是SWParameterType.SPReturnValue 时,即这个方法参数包含一个存储过程返回值,这个参数必须是传递参考的.

当SWCommandAttribute.CommandType值为SWCommandType.InsertUpdate时,ParameterType属性值可能是SWParameterType.Key 和 SWParameterType.Identity

InsertUpdate( 插入-更新 ) 命令
一个 INSERT 或者 UPDATE SQL语句,非常琐碎,但是却很常用.我在SqlWrapper库中添加下面的命令和参数,可以简单第创建插入和更新数据到表的方法.
SWCommandType.InsertUpdate标识创建一个 特定的  插入-更新 表达式.
SWCommandAttribute.CommandText 必须是一个表的名称.
SWParameterType.Identity标识 参数是一个标识表列,用来标识一个行.这个值必须被传递参考.
SWParameterType.Key 标识 这个参数是一个主键的一部分(不是标识表列),用来标识一个行.

下面是两个 插入-更新 的例子.

 

1.方法定义:
[SWCommand(SWCommandType.InsertUpdate, 
"Shippers")]
public abstract void ShippersInsertUpdate
    (
    [SWParameter(SWParameterType.Identity)]
ref int ShipperID,
    [SWParameter(
40)]string CompanyName,
    [SWParameter(
24)]string Phone
    );
SQL语句:
if(@ShipperID is NULL) 
begin  
    insert into [Shippers]([CompanyName], [Phone]) 
    values(@CompanyName, @Phone)  
    
    select @ShipperID 
= SCOPE_IDENTITY() 
end 
else 
begin  
    update [Shippers] 
set 
    [CompanyName]
=@CompanyName, 
    [Phone]
=@Phone 
    where [ShipperID]
=@ShipperID  
end
2.方法定义:
[SWCommand(SWCommandType.InsertUpdate, 
"Order Details")]
public abstract void OrderDetailsInsertUpdate
    (
    [SWParameter(SWParameterType.Key)]
int OrderID,
    [SWParameter(SWParameterType.Key)]
int ProductID,
    Decimal UnitPrice,
    Int16 Quantity,
    
float Discount
    );

SQL语句:

update [Order Details] 
set 
[OrderID]
=@OrderID, 
[ProductID]
=@ProductID, 
[UnitPrice]
=@UnitPrice, 
[Quantity]
=@Quantity, 
[Discount]
=@Discount 
where [OrderID]
=@OrderID and [ProductID]=@ProductID  

if (@@rowcount = 0)  
    insert into [Order Details]([OrderID], [ProductID], [UnitPrice], 
    [Quantity], [Discount]) 
    values(@OrderID, @ProductID, @UnitPrice, @Quantity, @Discount)

同你看到的一样,第一个例子中@ShipperID和NULL比较,默认的,这个值可能合适的是参数等于或者小于0.如果你要你能设置其他的值,你可以设置SWParameter.TreatAsNull属性,那么你设置的值将被转化为null.

在你的应用程序中创建数据访问层

SqlWrapper苦包含了基本的类:DataAccessLayerBase,它能够被利用很少的代码定制你自己的自定义数据访问层(DAL).所有要做的工作就是继承DataAccessLayerBase类,然后定义你要包装的类的属性如下:
public YourWrapperClass YourPropertyName
{
    get
    {
      return (YourWrapperClass)GetWrapped();
    }
}

这就是全部了.你可以添加任何其他你需要的成员.这个DAL的例子能创建上边的类Orders2,UserClass1.
public class MyDAL : DataAccessLayerBase
{
    public UserClass1 UserClass1{get{return (UserClass1)GetWrapped();}}
    public Orders2 Orders2{get{return (Orders2)GetWrapped();}}
}

这是一个DAL类的图:
 

这有一个如何使用你的数据访问层的例子:
MyDAL dal = new MyDAL();
dal.Init(cnn, true, true);
int c = dal.Orders2.CountByEmployee(6);
DataTable dt = dal.UserClass1.Method1();

在你使用一个DAL内的一个对象类,你要调用一个重载方法Init(),它继承于DataAccessLayerBase类.

public void Init(SqlConnection connection, bool autoCloseConnection,
          bool ownsConnection);
public void Init(string connectionString, bool autoCloseConnection);

这些方法非常重要.因为在你连接设置属性外,他们调用一个私有方法,GenerateAllWrapper(),它列举了你DAL层中类的所有方法.创建包装对象和保存它们到一个私有的哈希表,m_swTypes:
private void GenerateAllWrapped()
{
    MethodInfo[] mis = this.GetType().GetMethods();
    for(int i = 0; i < mis.Length; ++i)
    {
        Type type = mis[i].ReturnType;
        if(type.GetInterface(typeof(ISqlWrapperBase).FullName) ==
                 typeof(ISqlWrapperBase))
        {
            if(mis[i].Name.StartsWith("get_"))
            {
                if(!m_swTypes.ContainsKey(mis[i].Name))
                {
                    ISqlWrapperBase sw = WrapFactory.Create(type);
                    m_swTypes[mis[i].Name] = sw;
                }
            }
        }
    }
}

你曾经定义的属性,调用包含方法GetWrapped(),将查找一个调用方法的名字,从m_swTypes返回一个正确的对象
protected ISqlWrapperBase GetWrapped()
{
    MethodInfo mi = (MethodInfo)(new StackTrace().GetFrame(1).GetMethod());
    ISqlWrapperBase res = (ISqlWrapperBase)m_swTypes[mi.Name];
    if(res == null)
    {
        throw new SqlWrapperException("The object is not initialized.");
    }
    return res;
}

DataAccessLayerBase 使用下面三个方法,来简单第支持事务.
BeginTransaction() 和BeginTransaction(IsolationLevel iso) 打开一个新的事务.
RollbackTransaction() 回滚一个打开的事务.
CommitTransaction() 提交一个打开的事务.
包装类的Connection, Transaction 或者 AutoCloseTransaction属性将自动更新,当它们改变的时候.

另外,DataAccessLayerBase类还有几个方法(ExecuteDataSet(), ExecuteDataTable(), ExecuteScalar()和ExecuteNonQuery()),帮助你在特殊查询时使用sql语句.

在CodeProject上看了数据库的文章,感觉很好.性能也可以(感觉和访问数据库比,性能可以不计).就翻译了,水平有限,请指正. (翻译的不好的例子)
关于性能:
 1.利用Emit减少性能损失http://yok.cnblogs.com/archive/2005/11/03/267952.html
2.反射性能分析: http://www.chinaitclub.org/forums/350/ShowPost.aspx

注: 在.NET2.0中,插入和更新不能使用,发生错误.

分享到:
评论

相关推荐

    C# 数据访问层封装

    C#作为.NET框架的主要编程语言,提供了丰富的工具和库来构建高效的数据访问层。本示例"数据库管理,权限精确到库"将展示如何在C#中进行数据访问层的封装,实现对数据库的精细控制。 首先,我们需要理解数据访问层的...

    什么是三层架构_表现层/业务逻辑层/数据访问层

    这种架构模式将应用程序划分为三个主要部分:表现层(UI)、业务逻辑层(BLL)和数据访问层(DAL)。 表现层,或用户界面层(UI),是用户与系统交互的地方。这一层负责展示数据,接收用户输入,并处理用户触发的...

    《解剖PetShop》之二:PetShop数据访问层数之据库访问设计

    二、PetShop数据访问层之数据库访问设计  在系列一中,我从整体上分析了PetShop的架构设计,并提及了分层的概念。从本部分开始,我将依次对各层进行代码级的分析,以求获得更加细致而深入的理解。在PetShop 4.0中,...

    SQL数据生成器

    SQL数据生成器是一种工具,主要用于在数据库环境中快速创建和填充大量的测试或示例数据。它对于软件开发、性能测试、数据库设计验证等场景非常有用。通过使用这种工具,用户可以自定义数据规则,生成符合特定业务...

    ASP.NET c# SQL SERVER 2005连接数据库 代码 数据访问层

    ASP.NET c# SQL SERVER 2005连接数据库 代码 数据访问层 连接数据库的代码

    labview写入数据到sql server2005

    在Windows操作系统中,可以通过ODBC数据源管理器来配置新的数据源,选择适用于SQL Server的ODBC驱动,例如“SQL Server Native Client 10.0”(对应SQL Server 2008及更高版本),或者“SQL Server”(支持SQL ...

    微软企业库连接Oracle数据库的数据访问层

    【标题】:“微软企业库连接Oracle数据库的数据访问层”揭示了使用Microsoft Enterprise Library(ENTLIB)与Oracle数据库交互的关键技术。Microsoft Enterprise Library是.NET Framework下的一组可重用的应用程序块...

    全世界国家地区名称SQL数据

    标题中的“全世界国家地区名称SQL数据”指的是一个包含全球各国和地区名称的数据集合,它以SQL(结构化查询语言)的形式存在。SQL是用于管理和处理关系数据库的标准编程语言,用于存储、检索、更新和删除数据库中的...

    WinCC数据库SQL访问

    WinCC V6.2的数据库访问技术,结合了SQL Server 2005的强大功能和WinCC自身的创新特性,为工业自动化领域的数据管理和分析提供了坚实的基础。通过熟练掌握SSMS的使用和理解数据库架构,用户可以充分利用WinCC的潜力...

    SQL2000企业管理器绿色版

    SQL2000企业管理器是微软SQL Server 2000数据库系统的重要组成部分,它提供了一个图形化的用户界面,使得数据库管理员和开发人员能够轻松地管理和维护SQL Server实例。这个"SQL2000企业管理器绿色版"是精简版或者...

    SQL Server表数据导出成Insert语句的工具

    "SQL Server表数据导出成Insert语句的工具"是一个专门为此目的设计的应用程序,它能帮助数据库管理员和开发人员高效地生成插入语句,以便在其他数据库中重建同样的数据结构和内容。 1. **数据导出的需求**:在不同...

    最新淘宝商品类目数据.sql

    标题中的“最新淘宝商品类目数据.sql”表明这是一个SQL文件,包含了淘宝平台的商品类别数据。在电商领域,商品类目是组织和管理在线销售产品的一种方式,它类似于传统零售店的商品货架,帮助消费者快速找到他们感...

    SQLiteForExcel, 提供从VBA访问sql库的轻量包装器.zip

    SQLiteForExcel, 提供从VBA访问sql库的轻量包装器 概述是一个小型。开源的数据库引擎。 这个项目是用于Excel的,它是一个轻量级包装器,可以通过VBA访问sql数据库。 它为函数提供了高性能的路径,保留了调用的语义,...

    把sql表里面的数据导出到word里面

    在SQL数据库管理和日常办公中,有时我们需要将存储在SQL数据库中的数据导出到Microsoft Word文档中,以便于报告、分析或共享。这个过程涉及到数据库查询、数据处理和文档生成技术。下面将详细介绍如何实现这一操作。...

    Sql经典练习题库(附答案)

    4. **数据控制语言(Data Control Language, DCL)**:用于控制数据的安全性和完整性,包括授权(GRANT)、撤销权限(REVOKE)、提交事务(COMMIT)、回滚事务(ROLLBACK)等语句。 #### 五、经典SQL练习题解析 ##...

    全国省市县城市数据大全(执行sql语句并带数据库表结构)

    在这个数据集中,SQL语句可能是INSERT(插入数据)、SELECT(查询数据)、UPDATE(更新数据)和DELETE(删除数据)等,尤其是SELECT语句,可以用于获取特定级别的行政区域信息,例如,查询所有省份、某一省份下的...

    SQLServer OLAP实验详解(含数据)

    SQLServer的数据挖掘扩展了其OLAP功能,提供了预定义的算法,如关联规则、聚类、决策树和神经网络,用于发现数据中的模式和趋势。在实验中,你可能需要使用SQLServer的数据挖掘工具,如Data Mining Wizard,来创建和...

    sqlserver自动生成sql语句工具sqlserver转oracle

    这个过程涉及到SQL语法的转换,因为SQL Server和Oracle虽然都遵循SQL标准,但各自的语法特性和函数库有所不同。例如,SQL Server的T-SQL和Oracle的PL/SQL在存储过程编写上就有显著差异。 标签"sql 工具"表明我们...

    SQLServer2008数据导入到Oracle11g详解

    - 通过开始菜单中的“ODBC数据源”或者“控制面板 &gt; 管理工具 &gt; 数据源 (ODBC)”访问ODBC数据源管理器。 2. **创建新的数据源**: - 在ODBC数据源管理器中选择“用户DSN”或“系统DSN”,然后点击“添加”按钮。 ...

    中国所有唐诗数据(SQL文件)

    中国所有唐诗数据(SQL文件)。 在数据库管理工具执行SQL脚本即可,没有建库只有建表和插入语句,需要自己创建数据库。 包含中国所有唐诗。

Global site tag (gtag.js) - Google Analytics