这可能是一个古老而又善良的人。我正在使用System.Data.Common来实现可互换的Oracle / SQL Server / SQLite数据访问库。在构造函数期间,我获取连接字符串名称并使用它来确定基础提供程序类型。我这样做的原因是为每个提供程序处理不同的IDbParameter命名约定。例如,Oracle喜欢:参数,而SQL Server和SQLite喜欢@parameter。默认是?覆盖Oledb。
问题:这一切都是不必要的,是否有一些我想念的简单事情应该只是照顾这个?如果我的IDbCommand.CommandText =“选择id,来自my.table的名称,其中id =:id”我是否已被覆盖?现在我只是采用?作为默认值,然后在执行命令之前以RegEx的方式使用正确的参数标识符。
感谢。
/// <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位基本上算出“?”或“:”或“@”或其他东西。
UPDATE 这是我到目前为止处理细节的方式:
获取正确的参数字符串:
private void DetermineProviderSpecificParameters() { //检查支持的提供商。这样就可以限制参数化查询 //按空间范围正确创建。 string shortName = _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;
}
}
在我执行每个命令以“清理”或“参数化”它之前调用一个小帮手,或者我们称之为半asck:
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));
}
呸。仍然在寻找一个相对简单的解决方案,但到目前为止的建议当然值得赞赏。
答案 0 :(得分:1)
似乎没有针对此的约定或API。诸如nhibernate之类的ORM也为每个驱动程序实现了它们自己的占位符前缀映射。
答案 1 :(得分:1)
我为Salamanca做了类似的事情:见ParameterBuilder.cs。此代码使用:
DbCommandBuilder
上受保护的方法,通过反射调用(我只会在完全信任模式下工作):GetParameterPlaceholder
和GetParameterName
。DbConnection.GetSchema
返回的信息。在一个完美的世界里,我只能使用它,但我没看到到目前为止...... 问题是您需要参数的有效名称(Sql Server中为"@name"
,Oracle中为"name"
),以及SQL查询中的有效占位符(Sql中为"@name"
服务器,Oracle中的":name"
。
GetParameterName
会为您提供参数的有效名称。创建占位符:
GetParameterPlaceholder
。或查询DbMetaDataColumnNames.ParameterMarkerFormat
中包含的the schema for your connection值。您应该能够使用此字符串作为格式字符串来创建占位符,将前面的参数名称作为输入(暗示Sql Server的格式字符串为"{0}"
,Oracle的格式字符串为":{0}"
):< / p>
// DbConnection connection;
// string parameterName
DataRow schema=connection.GetSchema(DbMetaDataCollectionNames.DataSourceInformation).Rows[0];
string placeholder=string.Format(
CultureInfo.InvariantCulture,
(string)schema[DbMetaDataColumnNames.ParameterMarkerFormat],
name.Substring(0, Math.Min(parameterName.Length, (int)schema[DbMetaDataColumnNames.ParameterNameMaxLength]))
);
已经使用Sql Server,Access,Sqlite和Oracle对此进行了测试(但请注意,this will not work as is with ODP .NET ...)毫无疑问。
答案 2 :(得分:0)
您可以轻微击中性能并使用System.Data.OleDb类。这样,无论数据库如何,您都可以使用相同的代码。或者您可以使用像Unity这样的Inversion of Control框架。然后,您可以要求为数据库,参数以及调用者希望使用的参数等适当的工厂注入您的数据访问类。