使用System.Data.Common进行参数命名

时间:2009-08-10 19:58:00

标签: c# database

这可能是一个古老而又善良的人。我正在使用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 这是我到目前为止处理细节的方式:

  1. 获取正确的参数字符串:

    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;
        }
    }
    
  2. 在我执行每个命令以“清理”或“参数化”它之前调用一个小帮手,或者我们称之为半asck:

    private void MakeProviderSpecific(IDbCommand command)
    {
        foreach (IDataParameter param in command.Parameters)
        {
            param.ParameterName = GetProviderSpecificCommandText(param.ParameterName);
        }
        command.CommandText = GetProviderSpecificCommandText(command.CommandText);
    }
    
  3. 这需要做一点正则表达式:

    public string GetProviderSpecificCommandText(string rawCommandText)
    {
        return Regex.Replace(rawCommandText, @"\B\?\w+", new MatchEvaluator(SpecificParam));
    }
    
  4. 呸。仍然在寻找一个相对简单的解决方案,但到目前为止的建议当然值得赞赏。

3 个答案:

答案 0 :(得分:1)

似乎没有针对此的约定或API。诸如nhibernate之类的ORM也为每个驱动程序实现了它们自己的占位符前缀映射。

答案 1 :(得分:1)

我为Salamanca做了类似的事情:见ParameterBuilder.cs。此代码使用:

问题是您需要参数的有效名称(Sql Server中为"@name",Oracle中为"name"),以及SQL查询中的有效占位符(Sql中为"@name"服务器,Oracle中的":name"

  1. 通过正确的连接,GetParameterName会为您提供参数的有效名称。
  2. 创建占位符:

    • 通过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]))
      );
      
  3. 已经使用Sql Server,Access,Sqlite和Oracle对此进行了测试(但请注意,this will not work as is with ODP .NET ...)毫无疑问。

答案 2 :(得分:0)

您可以轻微击中性能并使用System.Data.OleDb类。这样,无论数据库如何,您都可以使用相同的代码。或者您可以使用像Unity这样的Inversion of Control框架。然后,您可以要求为数据库,参数以及调用者希望使用的参数等适当的工厂注入您的数据访问类。