最近接手了一个旧的系统,各种陈旧的问题比较多,其中最棘手的就是操作数据库的部分,具体如下:
1、核心库是一个最后修改时间为2008年的库,先不说有多陈旧,现在这个库只是一个DLL文件,没有源码,也已经没人知道里面都实现了些啥功能,就算你怀疑数据库读写有问题,也无法验证和调试,反编译出来的源码也没法用。
2、这个库用的是System.Data.OracleClient操作Oracle,问题很明显,依赖于Oracle客户端,区分32位和64位,一旦客户的Oracle客户端出点问题,系统就歇菜了,而且部署起来也不方便。
3、操作数据库用的全是拼写SQL语句,对我这种习惯了ORM的人,实在太痛苦了,而且对JSON和流数据的支持也不是很好,这两种数据都需要单独处理,无形中增加了操作数据库的次数。
明确了问题,也就知道了最终想要达到的效果,具体如下:
1、有源码,风险可控。
2、不依赖于Oracle客户端,不区分32位和64位,这个其实Oracle官方已经提供了解决方案,就是ODP.NET,最新版本已经快可以达到前面两个要求,而且提供了NUGET包,引用简单。
3、既要兼容旧有的DbHelper的操作方式,也要支持ORM的操作方式,一是因为原来代码量过大,不可能快速完全转到ORM,所以必须兼容旧有的操作方式,同时,ORM也是必须的,毕竟自己用着顺手。
知道了自己想要什么,于是,我就开始找可以做到这个库,功夫不负有心人,最终我找到了深蓝医生的SOD,完全满足我的要求,具体如下:
1、SOD完全开源,并提供使用指导。
2、SOD支持最新版本的ODP.NET,并提供了NUGET的获取方式,相当方便。
3、SOD不仅是一个ORM,还提供了DBHelper形式的数据库操作方式,不仅如此,更神奇的是,SOD支持执行SQL得到实体的操作方式,是不是很像Dapper.NET?
4、SOD支持现在大部分主流的数据库,以后要换库也是无缝对接。
5、客户反馈旧系统如果打开十几分钟没有操作,界面就会卡死,关了重新开,软件依然用不了,必须重启操作系统才能恢复正常,换了SOD之后,这个问题神奇的被修复了,看来真的是数据库读写有问题。不过也从侧面说明旧系统的异常处理和日志机制有些问题,这么严重的问题,既没有抛出异常,也没有记录日志,看来需要填的坑还是有一些的。
说了这么多废话,还是要来点干货,把我写的兼容旧系统的基于SOD的DbHelper给大家看看,写的不好,还希望多多指教,最后总结一句:
人生苦短,我用SOD,蜜!
SOD源码地址:
OSC@GIT:http://git.oschina.net/dxzyx/SOD
Codeplex:http://pwmis.codeplex.com/SourceControl/latest
GITHUB:https://github.com/znlgis/PDF.NET-SOD
NUGET地址:https://www.nuget.org/profiles/znlgis
using System;
using System.Collections.Generic;
using System.Data;
using Oracle.ManagedDataAccess.Client;
using PWMIS.DataMap.Entity;
using PWMIS.DataProvider.Adapter;
using PWMIS.DataProvider.Data;
namespace Db
{
/// <summary>
/// 数据库访问类
/// </summary>
public static class StaticDbHelper
{
private static AdoHelper _defaultDataBase;
/// <summary>
/// 获取或者设置默认的数据库操作对象,如果未设置将采用默认的配置进行实例化数据库操作对象。
/// 支持读写分离模式
/// </summary>
public static AdoHelper DefaultDataBase
{
get
{
var dataConInfomation = new DcicDbConnInfo();
DcicComnLib.Sys_GetOracleSetting(ref dataConInfomation);
return _defaultDataBase ??
MyDB.GetDBHelperByProviderString(
"PWMIS.DataProvider.Data.OracleDataAccess.Oracle,PWMIS.OracleClient",
$"Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST={dataConInfomation.Ip})(PORT={dataConInfomation.Port}))
(CONNECT_DATA=(SID={dataConInfomation.Sid})));User Id={dataConInfomation.UserId};Password={dataConInfomation.Pwd};");
}
set { _defaultDataBase = value; }
}
#region ORM
/// <summary>
/// 获取查询结果数量
/// </summary>
/// <param name="goql"></param>
/// <returns></returns>
public static int Count<T>(GOQL<T> goql) where T : EntityBase, new()
{
return goql.ToList(DefaultDataBase).Count;
}
/// <summary>
/// 判断是否存在查询结果
/// </summary>
/// <param name="goql"></param>
/// <returns></returns>
public static bool Exists<T>(GOQL<T> goql) where T : EntityBase, new()
{
var count = Count(goql);
return count > 0;
}
/// <summary>
/// 增加一条记录
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="model"></param>
/// <returns></returns>
public static bool Insert<T>(T model) where T : EntityBase, new()
{
var query = new EntityQuery<T>(DefaultDataBase);
var result = query.Insert(model);
return result == 1;
}
/// <summary>
/// 删除一条记录
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="model"></param>
/// <returns></returns>
public static bool Delete<T>(T model) where T : EntityBase, new()
{
var query = new EntityQuery<T>(DefaultDataBase);
var result = query.Delete(model);
return result == 1;
}
/// <summary>
/// 更新一条记录
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="model"></param>
/// <returns></returns>
public static bool Update<T>(T model) where T : EntityBase, new()
{
var query = new EntityQuery<T>(DefaultDataBase);
var result = query.Update(model);
return result == 1;
}
/// <summary>
/// 查询多条记录
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="oql"></param>
/// <returns></returns>
public static List<T> QueryList<T>(GOQL<T> oql) where T : EntityBase, new()
{
return oql.ToList(DefaultDataBase);
}
/// <summary>
/// 查询一条记录
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="oql"></param>
/// <returns></returns>
public static T QueryObject<T>(GOQL<T> oql) where T : EntityBase, new()
{
return oql.ToObject(DefaultDataBase);
}
#endregion
#region SQL TO ORM
/// <summary>
/// 查询多条记录
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="sql"></param>
/// <returns></returns>
public static List<T> QueryList<T>(string sql) where T : EntityBase, new()
{
return EntityQuery<T>.QueryList(DefaultDataBase.ExecuteDataReader(sql));
}
/// <summary>
/// 查询一条记录
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="sql"></param>
/// <returns></returns>
public static T QueryObject<T>(string sql) where T : EntityBase, new()
{
return EntityQuery<T>.QueryObject(DefaultDataBase.ExecuteDataReader(sql));
}
#endregion
#region SQL
/// <summary>
/// 获取DataTable
/// </summary>
/// <param name="sql"></param>
/// <returns></returns>
public static DataTable GetDataTable(string sql)
{
DataTable tableResult = null;
try
{
tableResult = DefaultDataBase.ExecuteDataSet(sql).Tables[0];
}
catch
{
// ignored
}
return tableResult;
}
/// <summary>
/// 获取查询结果数量
/// </summary>
/// <param name="sql"></param>
/// <returns></returns>
public static int GetCount(string sql)
{
var count = 0;
try
{
var obj = DefaultDataBase.ExecuteScalar("select count(*) from ( " + sql + " )");
count = Convert.ToInt32(obj);
}
catch
{
// ignored
}
return count;
}
/// <summary>
/// 执行SQL语句
/// </summary>
/// <param name="sql"></param>
/// <returns></returns>
public static bool Execute(string sql)
{
try
{
DefaultDataBase.ExecuteNonQuery(sql);
return true;
}
catch
{
return false;
}
}
/// <summary>
/// 判断是否存在查询结果
/// </summary>
/// <param name="sql"></param>
/// <returns></returns>
public static bool ExecuteCount(string sql)
{
var bok = false;
try
{
var count = GetCount(sql);
if (count > 0)
bok = true;
}
catch
{
// ignored
}
return bok;
}
/// <summary>
/// 返回数据表第一行、第一列的字段段值
/// </summary>
/// <param name="sql"></param>
/// <returns></returns>
public static string ExecuteString(string sql)
{
var result = "";
try
{
result = (string)DefaultDataBase.ExecuteScalar(sql);
}
catch
{
// ignored
}
return result;
}
/// <summary>
/// 保存Blob
/// </summary>
/// <param name="cmdSql"></param>
/// <param name="keyName"></param>
/// <param name="myBytes"></param>
public static void SetBlob(string cmdSql, string keyName, byte[] myBytes)
{
var p = new OracleParameter(keyName, OracleDbType.Blob);
p.Value = myBytes;
DefaultDataBase.ExecuteNonQuery(cmdSql, CommandType.Text, new IDataParameter[] { p });
}
/// <summary>
/// 获取Blob
/// </summary>
/// <param name="cmdSql"></param>
/// <returns></returns>
public static byte[] GetBlob(string cmdSql)
{
return (byte[])DefaultDataBase.ExecuteScalar(cmdSql);
}
#endregion
}
}