在写基于数据库的程序中发现,通常关系数据库中一个表可以抽象为一个类,数据表中的每条数据都可以看做是该类的一个实例。
例如用户表Users有三个字段:id(varchar2),name(Varchar2),age(number)。用户理所当然要抽象成一个类(当然,这里谈的是面向对象设计),而该类的数据成员应该是Users表中的三个字段。至于用户类的方法,总少不了增删改查这些操作,例如添加新用户,修改用户信息,查询用户等等。
问题来了,如果我们有N个表,要对这N个表进行操作,写N个类,他们的数据成员(其实就是数据表字段)不一样,却有着一些相同的方法(增删改查),是不是要给每一个类一一地写这些实现呢?如果N>10,你是否感觉很累呢?以后如果还有类似的项目,你又要重新再写N个类,买噶的,我都要疯了,不知道你有何感想?
我们是程序员,但不能傻傻的闷声写程序,那样键盘敲破了都不会有进步。写程序之前,想一想,我的代码怎么样才能设计的更加精巧更加容易复用呢?
我在前面的博客中好像写过利用抽象工厂模式实现不同数据库的自由切换(?时间太长,不大记得了)。这里再写一个抽象的数据表数据实体类作为基类,为他的每个子类实现增删改查这些数据库操作,子类只要向基类传入表名和列名就可以了。这样,以后每个项目你都不用再染指关于数据库的东西了。
首先是一个数据项类,该类把列名和数据绑定起来,方便操作。
然后是本文的核心,数据表实体对象类,比较长,呵呵
数据表实体对象类的应用列子,还以上面的用户表做例子吧.
如果对前面的数据库抽象工厂类感到疑惑,可以看看下面的两个工厂类:
抽象工厂:
具体的Oracle数据库工厂示例:
看了这么多代码,一定很晕吧,哈,可能是我的代码写的不够完美,如果有什么改进意见,请不吝赐教~
例如用户表Users有三个字段:id(varchar2),name(Varchar2),age(number)。用户理所当然要抽象成一个类(当然,这里谈的是面向对象设计),而该类的数据成员应该是Users表中的三个字段。至于用户类的方法,总少不了增删改查这些操作,例如添加新用户,修改用户信息,查询用户等等。
问题来了,如果我们有N个表,要对这N个表进行操作,写N个类,他们的数据成员(其实就是数据表字段)不一样,却有着一些相同的方法(增删改查),是不是要给每一个类一一地写这些实现呢?如果N>10,你是否感觉很累呢?以后如果还有类似的项目,你又要重新再写N个类,买噶的,我都要疯了,不知道你有何感想?
我们是程序员,但不能傻傻的闷声写程序,那样键盘敲破了都不会有进步。写程序之前,想一想,我的代码怎么样才能设计的更加精巧更加容易复用呢?
我在前面的博客中好像写过利用抽象工厂模式实现不同数据库的自由切换(?时间太长,不大记得了)。这里再写一个抽象的数据表数据实体类作为基类,为他的每个子类实现增删改查这些数据库操作,子类只要向基类传入表名和列名就可以了。这样,以后每个项目你都不用再染指关于数据库的东西了。
首先是一个数据项类,该类把列名和数据绑定起来,方便操作。
- /// <summary>
- /// 数据项类 包括数据库字段名称和值
- /// </summary>
- public class DataItem
- {
- private static IDatabaseFactory m_fac = SqlHelper.CreateDatabaseFactory(); //这个数据库抽象工厂,会在后面列出来
- private readonly string m_name;
- private object m_value;
- /// <summary>
- /// 构造 数据项实例
- /// </summary>
- /// <param name="name">数据库字段名称</param>
- public DataItem(string name)
- {
- this.m_name = name;
- }
- /// <summary>
- /// 获取 数据库字段名称
- /// </summary>
- public string Name
- {
- get { return m_name; }
- }
- /// <summary>
- /// 获取或设置 字段对应的值
- /// </summary>
- public object Value
- {
- get { return m_value; }
- set { m_value = value; }
- }
- /// <summary>
- /// 获取 值在SQL语句中的字符串表示
- /// </summary>
- public string ValueSqlString
- {
- get
- {
- if (m_value == null)
- {
- return "null";
- }
- else if (m_value.GetType() == typeof(string))
- {
- return "'" + m_value.ToString().Replace("'","''") + "'";
- }
- else if (m_value.GetType() == typeof(int))
- {
- return m_value.ToString();
- }
- else if (m_value.GetType() == typeof(DateTime))
- {
- return m_fac.ToDBTimeString(Convert.ToDateTime(m_value));
- }
- else
- {
- return "null";
- }
- }
- }
- public override string ToString()
- {
- return m_name + "="+ValueSqlString;
- }
- }
- /// <summary>
- /// 与数据库表紧密相关 的 实体类
- /// </summary>
- public class DataTableObject
- {
- protected readonly string m_tableName;
- protected DataItem m_key;
- protected IList<DataItem> m_col;
- /// <summary>
- /// 构造 一个数据表实体类
- /// </summary>
- /// <param name="tableName">表名</param>
- /// <param name="keyName">主键名</param>
- /// <param name="colName">列名</param>
- protected DataTableObject(string tableName,string keyName,params string[] colName)
- {
- m_col = new List<DataItem>();
- this.m_tableName = tableName;
- this.m_key = new DataItem(keyName);
- if (colName==null) return;
- foreach (string col in colName)
- {
- m_col.Add(new DataItem(col));
- }
- }
- /// <summary>
- /// 构造 一个数据表实体类
- /// </summary>
- /// <param name="key">主键值</param>
- /// <param name="tableName">表名</param>
- /// <param name="keyName">主键名</param>
- /// <param name="colName">列名</param>
- protected DataTableObject(object key,string tableName, string keyName,params string[] colName)
- :this(tableName,keyName,colName)
- {
- m_key.Value = key;
- }
- /// <summary>
- /// 获取或设计 主键值
- /// </summary>
- public object Key
- {
- get
- {
- return m_key.Value;
- }
- set
- {
- this.m_key.Value = value;
- this.Load();
- }
- }
- /// <summary>
- /// 获取 指定列值
- /// </summary>
- /// <param name="index">列索引 依照构造函数传入的列顺序 从0开始</param>
- /// <returns></returns>
- public object GetDataValue(int index)
- {
- if (index > m_col.Count - 1) return null;
- if (m_col[index].Value == null) this.Load();
- return m_col[index].Value;
- }
- /// <summary>
- /// 获取 指定列值
- /// </summary>
- /// <param name="columnName">列名称</param>
- /// <returns></returns>
- public object GetDataValue(string columnName)
- {
- foreach (DataItem di in m_col)
- {
- if (di.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase))
- {
- if (di.Value == null) this.Load();
- return di.Value;
- }
- }
- return null;
- }
- /// <summary>
- /// 设置 指定列值
- /// </summary>
- /// <param name="index">列索引 依照构造函数传入的列顺序 从0开始</param>
- /// <param name="value">新的列值</param>
- /// <returns>设置是否成功</returns>
- public bool SetDataValue(int index, object value)
- {
- if (index > m_col.Count - 1) return false;
- m_col[index].Value = value;
- return true;
- }
- /// <summary>
- /// 设置 指定列值
- /// </summary>
- /// <param name="columnName">列名</param>
- /// <param name="value">新的列值</param>
- /// <returns>设置是否成功</returns>
- public bool SetDataValue(string columnName, object value)
- {
- foreach (DataItem di in m_col)
- {
- if (di.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase))
- {
- di.Value = value;
- return true;
- }
- }
- return false ;
- }
- /// <summary>
- /// 根据主键值 重新从数据库中加载数据
- /// </summary>
- /// <returns>加载是否成功</returns>
- public virtual bool Load()
- {
- if (m_key.Value == null)
- {
- Logger.LogText("不能读取数据,主键值为空.主键:"+m_key.Name);
- return false;
- }
- StringBuilder sbSql = new StringBuilder("select ");
- foreach (DataItem di in m_col)
- {
- sbSql.Append(di.Name);
- sbSql.Append(",");
- }
- int len = sbSql.Length;
- sbSql.Remove(len - 1, 1);
- sbSql.Append(" from ");
- sbSql.Append(m_tableName);
- sbSql.Append(" where ");
- sbSql.Append(m_key.Name);
- sbSql.Append("=");
- sbSql.Append(m_key.ValueSqlString);
- DataSet ds = SqlHelper.ExecuteQuery(sbSql.ToString());
- if (ds == null)
- {
- Logger.LogText("数据库插入操作失败.");
- return false;
- }
- if (ds.Tables[0].Rows.Count < 1)
- {
- ds.Dispose();
- return false;
- }
- int index = 0;
- DataRow dr = ds.Tables[0].Rows[0];
- foreach (DataItem di in m_col)
- {
- di.Value = dr[index++];
- }
- return true;
- }
- /// <summary>
- /// 将本条记录插入数据库
- /// </summary>
- /// <returns>插入是否成功</returns>
- public virtual bool Insert()
- {
- StringBuilder sbSql = new StringBuilder("insert into ");
- sbSql.Append(m_tableName);
- sbSql.Append(" (");
- foreach (DataItem di in m_col)
- {
- sbSql.Append(di.Name);
- sbSql.Append(",");
- }
- sbSql.Remove(sbSql.Length-1,1);
- sbSql.Append(") values (");
- foreach (DataItem di in m_col)
- {
- sbSql.Append(di.ValueSqlString);
- sbSql.Append(",");
- }
- sbSql.Remove(sbSql.Length - 1, 1);
- sbSql.Append(")");
- int result = SqlHelper.ExecuteNonQuery(sbSql.ToString());
- if(result>0)
- return true;
- return false;
- }
- /// <summary>
- /// 将本条记录的更新 写入数据库
- /// </summary>
- /// <returns>更新是否成功</returns>
- public virtual bool Update()
- {
- StringBuilder sbSql = new StringBuilder("update ");
- sbSql.Append(m_tableName);
- sbSql.Append(" set ");
- foreach (DataItem di in m_col)
- {
- sbSql.Append(di.Name);
- sbSql.Append("=");
- sbSql.Append(di.ValueSqlString);
- sbSql.Append(",");
- }
- sbSql.Remove(sbSql.Length - 1, 1);
- sbSql.Append(" where ");
- sbSql.Append(m_key.Name);
- sbSql.Append("=");
- sbSql.Append(m_key.ValueSqlString);
- int result = SqlHelper.ExecuteNonQuery(sbSql.ToString());
- if (result > 0)
- return true;
- return false;
- }
- /// <summary>
- /// 将本条记录从数据库中删除
- /// </summary>
- /// <returns>删除是否成功</returns>
- public virtual bool Delete()
- {
- StringBuilder sbSql = new StringBuilder("delete from ");
- sbSql.Append(m_tableName);
- sbSql.Append(" where ");
- sbSql.Append(m_key.Name);
- sbSql.Append("=");
- sbSql.Append(m_key.ValueSqlString);
- int result = SqlHelper.ExecuteNonQuery(sbSql.ToString());
- if (result > 0)
- return true;
- return false;
- }
- /// <summary>
- /// 获取 数据表中所有记录的对象列表
- /// </summary>
- /// <param name="tabName">表名</param>
- /// <param name="keyName">主键名</param>
- /// <param name="colName">列名</param>
- /// <returns>数据表中所有记录的对象列表</returns>
- protected static IList<DataTableObject> GetAll(string tabName,string keyName,params string[] colName)
- {
- IList<DataTableObject> list = new List<DataTableObject>();
- StringBuilder sbSql = new StringBuilder("select ");
- sbSql.Append(keyName);
- foreach(string name in colName)
- {
- sbSql.Append(",");
- sbSql.Append(name);
- }
- sbSql.Append(" from ");
- sbSql.Append(tabName);
- DataSet ds = SqlHelper.ExecuteQuery(sbSql.ToString());
- if (ds == null)
- {
- Logger.LogText("数据库查询操作失败.");
- return null;
- }
- int len = colName.Length;
- foreach (DataRow dr in ds.Tables[0].Rows)
- {
- DataTableObject obj = new DataTableObject(tabName, keyName, colName);
- obj.Key = dr[0];
- for (int i = 0; i <len; i++)
- {
- obj.SetDataValue(i, dr[i+1]);
- }
- list.Add(obj);
- }
- return list;
- }
- }
- public class User:DataTableObject
- {
- private const string tabName = "Users";
- private const string keyName = "id";
- private static readonly string[] colName = { "name","age"};
- public User():base(tabName,keyName,colName) { }
- public User(int id) : base(id, tabName, keyName, colName) { }
- public int ID
- {
- get
- {
- if (base.Key == null) return -1;//出错
- return Convert.ToInt32(base.Key);
- }
- set
- {
- base.Key = value;
- }
- }
- public string Name
- {
- get
- {
- if (base.GetDataValue(0) == null) base.Load(); //如果为空则重新载入
- return base.GetDataValue(0).ToString();
- }
- set
- {
- base.GetDataValue(0) = value;
- }
- }
- public int Age
- {
- get
- {
- if (base.GetDataValue("age") == null) base.Load(); //如果为空则重新载入
- return Convert.ToInt32(base.GetDataValue("age"));
- }
- set
- {
- base.GetDataValue("age") = value;
- }
- }
- //增删改查操作均继承自父类,此处不需要重写,如有需要也可以重写
- }
如果对前面的数据库抽象工厂类感到疑惑,可以看看下面的两个工厂类:
抽象工厂:
- /// <summary>
- /// 数据库工厂接口
- /// </summary>
- public interface IDatabaseFactory
- {
- /// <summary>
- /// 获取 数据库连接实例
- /// </summary>
- /// <returns>连接实例</returns>
- IDbConnection GetConnection();
- /// <summary>
- /// 获取 数据库命令实例
- /// </summary>
- /// <returns>命令实例</returns>
- IDbCommand GetCommand();
- /// <summary>
- /// 获取 数据适配器实例
- /// </summary>
- /// <returns>数据适配器实例</returns>
- IDbDataAdapter GetDataAdapter();
- /// <summary>
- /// 将指定时间转换成SQL语句
- /// </summary>
- /// <param name="time">时间</param>
- /// <returns>SQL语句</returns>
- string ToDBTimeString(DateTime time);
- }
- /// <summary>
- /// Oracle数据库相关对象 工厂(同一对象关于多线程不安全)
- /// </summary>
- public class OracleFactory:IDatabaseFactory
- {
- //数据库连接字符串
- private readonly string m_strConn = Config.Instance.ConnenctionString;
- private IDbConnection m_conn;
- private IDbCommand m_cmd;
- private IDbDataAdapter m_adapter;
- /// <summary>
- /// 获取 数据库连接实例
- /// </summary>
- /// <returns>数据库连接实例</returns>
- public IDbConnection GetConnection()
- {
- if (m_conn == null)
- {
- m_conn = new OracleConnection();
- m_conn.ConnectionString = m_strConn;
- }
- return m_conn;
- }
- /// <summary>
- /// 获取 数据库命令实例
- /// </summary>
- /// <returns>数据库命令实例</returns>
- public IDbCommand GetCommand()
- {
- if (m_cmd == null)
- {
- m_cmd = new OracleCommand();
- }
- return m_cmd;
- }
- /// <summary>
- /// 获取 数据库数据适配器实例
- /// </summary>
- /// <returns>数据库数据适配器实例</returns>
- public IDbDataAdapter GetDataAdapter()
- {
- if (m_adapter == null)
- m_adapter = new OracleDataAdapter();
- return m_adapter;
- }
- public string ToDBTimeString(DateTime time)
- {
- return String.Format("to_date('{0}','yyyy-mm-dd hh24:mi:ss')",time);
- }
- }
看了这么多代码,一定很晕吧,哈,可能是我的代码写的不够完美,如果有什么改进意见,请不吝赐教~