【发布时间】:2009-08-11 16:09:52
【问题描述】:
这可能是老歌,但很好。我将 System.Data.Common 用于可互换的 Oracle/SQL Server/SQLite 数据访问库。在构造函数期间,我获取连接字符串名称并使用它来确定底层提供程序类型。我这样做的原因是为每个提供者处理不同的 IDbParameter 命名约定。例如,Oracle 喜欢 :parameter,而 SQL Server 和 SQLite 喜欢 @parameter。默认值为 ?覆盖 Oledb。
问题:这一切都是不必要的吗?我是否缺少一些简单的东西来解决这个问题?如果我的 IDbCommand.CommandText = "select id, name from my.table where id = :id" 我被覆盖了吗?现在我只是采用?作为默认值,然后在执行命令之前使用正则表达式找到正确的参数标识符。
谢谢。
/// <summary>
/// Initializes a new instance of the <see cref="RelationalGateway"/> class.
/// </summary>
/// <remarks>You must pass in the name of the connection string from the application configuration
/// file rather than the connection string itself so that the class can determine
/// which data provider to use, e.g., SqlClient vs. OracleClient.</remarks>
public RelationalGateway(string connectionStringName)
{
if (string.IsNullOrEmpty(connectionStringName)) throw new ArgumentNullException("connectionStringName");
if (ConfigurationManager.ConnectionStrings[connectionStringName] == null ||
ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString.Length == 0 ||
ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName.Length == 0)
{
throw new InvalidOperationException(string.Format(
"The configuration file does not contain the {0} connection ",
connectionStringName) +
"string configuration section or the section contains empty values. Please ensure the " +
"configuration file has the appropriate values and try again.");
}
_connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
_providerName = ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName;
_theProvider = DbProviderFactories.GetFactory(_providerName);
_adapter = _theProvider.CreateDataAdapter();
//GetConnection();
DetermineProviderSpecificParameters();
}
DetermineProviderSpecificParameters 位基本上算出“?”或“:”或“@”或其他。
更新 以下是我目前处理细节的方式:
-
获取正确的参数字符串:
私人无效的DefineProviderSpecificParameters() { // 检查支持的提供者。这是为了限制参数化查询 // 按空间范围正确创建。 字符串短名称 = _providerName.Substring(_providerName.LastIndexOf(".") + 1);
switch (shortName) { case "SqlClient": _param = "@"; _ql = "["; _qr = "]"; break; case "SQLite": _param = "@"; _ql = string.Empty; _qr = string.Empty; break; case "OracleClient": _param = ":"; _ql = string.Empty; _qr = string.Empty; break; default: _param = "?"; _ql = string.Empty; _qr = string.Empty; break; } } -
在我执行每个命令之前调用一个小助手来“清理”或“参数化”它,或者我们称之为半途而废的黑客:
private void MakeProviderSpecific(IDbCommand command) { foreach (IDataParameter param in command.Parameters) { param.ParameterName = GetProviderSpecificCommandText(param.ParameterName); } command.CommandText = GetProviderSpecificCommandText(command.CommandText); } -
这需要一点正则表达式来做:
public string GetProviderSpecificCommandText(string rawCommandText) { return Regex.Replace(rawCommandText, @"\B\?\w+", new MatchEvaluator(SpecificParam)); }
哎呀。仍在寻找一个相对简单的解决方案,但到目前为止的建议肯定是值得赞赏的。
【问题讨论】:
-
不确定,但可以选择 NHibernate。
-
我正在将 NHibernate 用于其他项目,但这是我的其他开发人员使用的实用程序库,它为他们提供了一种快速但不太脏的 Db 访问方法。另外,我将其用作反开源客户的代码核心。是的,我手卷数据访问代码的次数超出了我的想象! :-(