2009-08-10 175 views
2

这可能是一个古老而又好吃的东西。我正在使用System.Data.Common作为可互换的Oracle/SQL Server/SQLite数据访问库。在构造函数中,我使用连接字符串名称并使用它来确定基础提供程序类型。我这样做的原因是为每个提供者处理不同的IDbParameter命名约定。例如,Oracle喜欢:参数,而SQL Server和SQLite像@parameter。默认是?以涵盖Oledb。使用System.Data.Common的参数命名

问题:这一切都是不必要的,是否有一些简单的东西我错过了,应该简单地照顾这个?如果我的IDbCommand.CommandText =“选择ID,名称来自my.table其中id =:id”我是否覆盖?现在我只是采用?作为默认值,然后在执行命令之前RegEx'ing我的方式到正确的参数标识符。

谢谢。

 /// <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. 得到正确的参数字符串:

    私人无效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. 调用一个小帮手之前,我执行每个命令“cleanify”或“parameterific”,或无论我们称之为半称职的黑客:

    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)); 
    } 
    

呸。仍在寻找一个相对简单的解决方案,但迄今为止的建议无疑是值得赞赏的

+0

不确定,但做你正在做的是NHibernate的一个选项。 – Amy 2009-08-10 20:21:20

+0

我为其他项目使用NHibernate,但这是我的其他开发人员使用的实用程序库,使他们有一个快速但不太脏的Db访问方法。此外,我将这作为我的代码的核心,用于反开源的客户端。是的,我手卷数据访问代码的次数比我想象的要多! :-( – Dylan 2009-08-10 21:55:32

回答

1

我为Salamanca做了这样的事情:请参阅ParameterBuilder.cs。该代码使用:

的事情是,你需要一个有效的名称为您的参数("@name"在SQL Server中,"name"在甲骨文)以及SQL查询中的有效占位符(Sql Server中的"@name",Oracle中的":name")。

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

    • 或者通过GetParameterPlaceholder
    • 或查询the schema for your connection中包含的DbMetaDataColumnNames.ParameterMarkerFormat值。您应该能够使用此字符串作为格式字符串,回吐此前的参数名称作为输入来创建占位符(这意味着格式字符串"{0}"对于SQL Server和":{0}"用于Oracle):

      // 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 ...)。

+0

谢谢,Mac。这似乎回答了我的问题。还有其他一些技巧的萨拉曼卡代码。干杯。 – Dylan 2009-08-11 19:35:53

1

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

+0

其实这就是我目前实现的方法,我会发布更多的代码,这样你就可以看到我现在正在做什么 – Dylan 2009-08-10 21:57:19

0

你可以轻微的表现击中并使用System.Data.OleDb类。这样,无论数据库如何,您都可以使用相同的代码。或者你可以使用控制反转框架,如Unity。然后你可以要求你的数据访问类被注入适当的数据库工厂,参数以及调用者想要使用的参数。

+0

这是一个选项,但我宁愿避免使用IoC框架对于我认为是实用程序类的东西 - 对于我的初级开发人员来说太复杂了,更不用说我的客户了(咨询限制了我的选项) – Dylan 2009-08-10 21:59:14