2009-08-10 173 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