现在的位置: 首页 > 综合 > 正文

使用泛型和反射,打造我们的完美实体基类(全文)

2014年01月30日 ⁄ 综合 ⁄ 共 8203字 ⁄ 字号 评论关闭

使用泛型和反射,打造我们的完美实体基类

 

 

背景

 

我在开发的过程中,实体和数据库的访问是一直要接触和编写的代码,考虑到团队中初学者比较多,我一直希望有一种方式可以改善目前编码的困境:

ADO.Net的代码对于初学者来讲比较麻烦,需要他们更多的对ADO.Net有所了解。

将数据库的值为实体属性赋值是一个比较繁琐的过程,程序员容易厌倦这个重复工作,或数据类型,或属性名称的赋值错误。

对于一对多的实体模型开发中,程序员很容易的将一对多的实体对象相互的关联错误。

 

我们当然可以使用一些自动化的工具来辅助,或者采用类似Hibernate的框架或VS2008SP1的一些新功能来实现,但我们又需要在我们的实体中有些更灵活的控制。

 

因此作为开发团队的技术管理人员,我必须要设计一种更好的模式来解决以上的事项。

 

正文中,我们将逐步的阐述我的设计思路。

 

 

 

一、打造DataProvider

 

ADO.Net的封装已经有很多的实现了,但我总感觉那些实现还是没有透明化使用者对ADO.Net的了解。比如说很多人推崇的Enterprise LibraryDataAccess,我认为就是封装不够彻底。我理想中封装彻底的ADO.Net对象是,使用者不需要(或尽可能的少)了解任何,而DataAccess还是需要使用者直接的处理很多ADO.Net的对象。而我需要的ADO.Net的封装希望使用者,仅给予SQL命令,赋值参数,并获取结果即可。

 

 

1.1定义DataProvide

 

定义SqlDataProvider

/// <summary>

/// SQL数据提供者的实现

/// </summary>

public class SqlDataProvider : DataProviders.IDataProvider

{

 

}

 

 

1.2定义DataProviders.IDataProvider

 

DataProviders.IDataProvider是我定义的一个接口,我希望将来所有的数据提供者都能实现该接口,以便利用依赖倒置实现抽象工厂。

 

 

定义DataProviders.IDataProvider接口

public interface IDataProvider

{

    void AddParameters(string parname, Guid value);

    void AddParameters(string parname, long value);

    void AddParameters(string parname, string value);

    void AddParameters(string parname, string value, DataProviders.StringFamily dataType);

    void AddParameters(string parname, string value, DataProviders.StringFamily dataType, int size);

    void AddParameters(string parname, float value);

    void AddParameters(string parname, decimal value);

    void AddParameters(string parname, DateTime value);

    void AddParameters(string parname, DateTime value, DataProviders.DateFamily dataType);

    void AddParameters(string parname, int value);

    void AddParameters(string parname, object value);

    void AddParameters(string parname, System.Drawing.Bitmap value);

    void AddParameters(string parname, byte[] value);

    void AddParameters(string parname, byte[] value, DataProviders.ByteArrayFamily dataType);

    void AddParameters(string parname, bool value);

    void AddParameters(string parname, short value);

    void AddParameters(string parname, byte value);

    System.Data.CommandType CommandType { get; set; }

    string ConnectionString { get; }

    System.Data.DataSet ExecuteDataSet();

    System.Data.DataTable ExecuteDataTable();

    void ExecuteReader(ReadData readData);

    int ExecuteNonQuery();

    object ExecuteScalar();

    string SQL { get; set; }

}

 

public delegate void ReadData(System.Data.IDataReader dataReadre);

 

从该接口可以看到,实现的DataProvider封装了关于具体的连接对象,命令对象和参数类型的信息。

 

 

1.3实现DataProvider基础部分

 

SqlDataProvider类实现(基础部分)

private static System.Data.SqlClient.SqlConnection conn;

private System.Data.SqlClient.SqlCommand cmd;

 

/// <summary>

/// 默认构造函数

/// </summary>

public SqlDataProvider()

{

 

}

 

/// <summary>

/// 接受连接字符串

/// </summary>

/// <param name="connstr"></param>

public SqlDataProvider(string connstr)

    : this(connstr, "")

{

 

}

 

/// <summary>

/// 接受连接字符串和sql字符串

/// </summary>

/// <param name="connstr"></param>

/// <param name="sql"></param>

public SqlDataProvider(string connstr, string sql)

{

    conn = new System.Data.SqlClient.SqlConnection(connstr);

    cmd = new System.Data.SqlClient.SqlCommand();

    cmd.Connection = conn;

    cmd.CommandText = sql;

}

 

/// <summary>

/// 需要执行的SQL命令

/// </summary>

public string SQL

{

    set

    {

        cmd.CommandText = value;

    }

    get

    {

        return cmd.CommandText;

    }

}

 

/// <summary>

/// 当前的连接字符串

/// </summary>

public string ConnectionString

{

    get

    {

        return conn.ConnectionString;

    }

}

 

/// <summary>

/// 设置命令的类型

/// </summary>

public System.Data.CommandType CommandType

{

    set

    {

        cmd.CommandType = value;

    }

    get

    {

        return cmd.CommandType;

    }

}

 

 

从上述代码可以观察到,我们的DataProvider只向用户暴露了两个字符串数据:连接字符串和SQL指令字符串。而将ADO.Net特有的ConnectionCommand封装起来了。由于用户不需要了解到具体实例化的ConnectionCommand,则为以后对其他数据源提供者的扩展带来了机会。

 

 

1.4实现DataProvider数据执行部分

 

SqlDataProvider类实现(数据执行部分)

/// <summary>

/// 将SqlDataReader提交给具体的委托器处理

/// </summary>

/// <param name="readData"></param>

public void ExecuteReader(ReadData readData)

{

    using (conn)

    {

        conn.Open();

        System.Data.SqlClient.SqlDataReader dr = cmd.ExecuteReader();

        readData(dr);

        conn.Close();

    }

}

 

/// <summary>

/// 对连接执行 Transact-SQL 语句并返回受影响的行数

/// </summary>

/// <returns></returns>

public int ExecuteNonQuery()

{

    int result = -1;

    using (conn)

    {

        conn.Open();

        result = cmd.ExecuteNonQuery();

        conn.Close();

    }

    return result;

}

 

/// <summary>

/// 执行查询,并返回查询所返回的结果集中第一行的第一列。忽略其他列或行

/// </summary>

/// <returns></returns>

public object ExecuteScalar()

{

    object result = null;

    using (conn)

    {

        conn.Open();

        result = cmd.ExecuteScalar();

        conn.Close();

    }

    return result;

}

 

 

/// <summary>

/// 执行查询,并返回查询的DataSet

/// </summary>

/// <returns></returns>

public System.Data.DataSet ExecuteDataSet()

{

    System.Data.DataSet datadet = new System.Data.DataSet();

    using (conn)

    {

        System.Data.SqlClient.SqlDataAdapter adapter = new System.Data.SqlClient.SqlDataAdapter();

        adapter.SelectCommand = cmd;

        conn.Open();

        adapter.Fill(datadet);

        conn.Close();

    }

    return datadet;

}

 

/// <summary>

/// 执行查询,并返回查询的Table

/// </summary>

/// <param name="tableIndex"></param>

/// <returns></returns>

public System.Data.DataTable ExecuteDataSet(int tableIndex)

{

    System.Data.DataSet datadet = ExecuteDataSet();

    if (datadet.Tables.Count > 0 && tableIndex < datadet.Tables.Count)

    {

        return datadet.Tables[tableIndex];

    }

    else

    {

        return null;

    }

}

 

/// <summary>

/// 执行查询,并返回查询的Table

/// </summary>

/// <returns></returns>

public System.Data.DataTable ExecuteDataTable()

{

    System.Data.DataTable table = new System.Data.DataTable();

    using (conn)

    {

        System.Data.SqlClient.SqlDataAdapter adapter = new System.Data.SqlClient.SqlDataAdapter();

        adapter.SelectCommand = cmd;

        conn.Open();

        adapter.Fill(table);

        conn.Close();

    }

    return table;

}

 

 

DataProvider提供ExecuteReaderExecuteNonQueryExecuteScalarExecuteDataSetExecuteDataTable方法,向使用者封装了两种不同的信息:

对执行数据访问的过程(Open后要Close等)已经在执行过程中的辅助对象(DataAdapter)信息。使用者仅需要简单的调用上述的方法,既可以得到他所关注的数据。

 

 

1.5实现DataProvider参数部分

 

SqlDataProvider类实现(参数部分)

/// <summary>

/// 添加一个Variant类型数据

/// </summary>

/// <param name="parname"></param>

/// <param name="value"></param>

public void AddParameters(string parname, object value)

{

    cmd.Parameters.Add(parname, System.Data.SqlDbType.Variant).Value = value;

}

 

/// <summary>

/// 添加一个Bit类型数据

/// </summary>

/// <param name="parname"></param>

/// <param name="value"></param>

public void AddParameters(string parname, bool value)

{

    cmd.Parameters.Add(parname, System.Data.SqlDbType.Bit).Value = value;

}

 

/// <summary>

/// 添加一个TinyInt类型数据

/// </summary>

/// <param name="parname"></param>

/// <param name="value"></param>

public void AddParameters(string parname, byte value)

{

    cmd.Parameters.Add(parname, System.Data.SqlDbType.TinyInt).Value = value;

}

 

/// <summary>

/// 添加一个SmallInt类型数据

/// </summary>

/// <param name="parname"></param>

/// <param name="value"></param>

public void AddParameters(string parname, short value)

{

    cmd.Parameters.Add(parname, System.Data.SqlDbType.SmallInt).Value = value;

}

 

/// <summary>

/// 添加一个Int类型数据

/// </summary>

/// <param name="parname"></param>

/// <param name="value"></param>

public void AddParameters(string parname, int value)

{

    cmd.Parameters.Add(parname, System.Data.SqlDbType.Int).Value = value;

}

 

/// <summary>

/// 添加一个BigInt类型数据

/// </summary>

/// <param name="parname"></param>

/// <param name="value"></param>

public void AddParameters(string parname, long value)

{

    cmd.Parameters.Add(parname, System.Data.SqlDbType.BigInt).Value = value;

}

 

 

/// <summary>

/// 添加一张图片

/// </summary>

/// <param name="parname"></param>

/// <param name="value"></param>

public void AddParameters(string parname, System.Drawing.Bitmap value)

{

    System.IO.MemoryStream ms = new System.IO.MemoryStream();

    value.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);

    AddParameters(parname, ms.ToArray(), ByteArrayFamily.Image);

}

 

 

/// <summary>

/// 添加一个Timestamp类型

/// </summary>

/// <param name="parname"></param>

/// <param name="value"></param>

public void AddParameters(string parname, byte[] value)

{

    AddParameters(parname, value, ByteArrayFamily.Timestamp);

}

 

/// <summary>

/// 添加一个字节数组族类型数据

/// </summary>

/// <param name="parname"></param>

/// <param name="value"></param>

/// <param name="dateType"></param>

public void AddParameters(string parname, byte[] value, ByteArrayFamily dataType)

{

    cmd.Parameters.Add(parname, DataTypeAdapter.ConvertSqlDbType(dataType)).Value = value;

}

 

 

 

/// <summary>

/// 添加一个字符类型数据,默认是NVarChar,长度是value.Length

/// </summary>

/// <param name="parname"></param>

/// <param name="value"></param>

public void AddParameters(string parname, string value)

{

    AddParameters(parname, value, StringFamily.NVarChar, value.Length);

}

 

/// <summary>

/// 添加一个字符族类型数据

/// </summary>

/// <param name="parname"></param>

抱歉!评论已关闭.