2009-08-05 49 views
2

我在我的應用程序中有幾個強類型的數據集。編寫更新數據的方法變得單調乏味,因爲每個表都有幾個表。我想創建一個可以輕鬆更新所有表的通用函數。我不介意是否必須爲每個DataSet創建其中的一個,但如果一個函數可以處理所有這些,那將非常棒!通用DataTable&TableAdaptor更新與反射(C#)

將會有任何數量的新記錄,更新記錄或刪除記錄,並且每行都應該正確標記。這個功能應該只是處理實際的保存。這是我到目前爲止:

private bool SaveData(object oTableAdaptor, object ds) 
    { 
     try 
     { 
      Type oType = oTableAdaptor.GetType(); 
      MethodInfo[] oMethodInfoArray = oType.GetMethods(); 

      foreach (MethodInfo oMI in oMethodInfoArray) 
      { 
       if (oMI.Name == "Update") 
       { 
        ParameterInfo[] oParamaterInfoArray = oMI.GetParameters(); 
        foreach (ParameterInfo oPI in oParamaterInfoArray) 
        { 
         Type DsType = null; 

         if (oPI.ParameterType.Name == "NameOfDataSet") 
         { 
          DsType = typeof(MyDataSet); 

          // get a list of the changed tables??? 
         } 

         if (((DataSet)ds).HasChanges() == true) 
         { 
          if (oPI.ParameterType == DsType) 
          { 
           object[] values = { ds }; 
           try 
           { 
            oMI.Invoke(oTableAdaptor, values); 
           } 
           catch (Exception ex) 
           { 
            System.Diagnostics.Debug.WriteLine(oTableAdaptor.GetType().Name + Environment.NewLine + ex.Message); 
           } 
          } 
         } 

        } 
       } 
      } 
     } 
     catch (Exception Exp) 
     { 
      System.Diagnostics.Debug.WriteLine(Exp.Message); 
      if (Exp.InnerException != null) System.Diagnostics.Debug.WriteLine(Exp.InnerException.Message); 

      return false; 
     } 

     return true; 

我已經適應了另一位代碼另一位開發人員在另一個應用程序中的代碼。到目前爲止,主要區別在於他傳入了dataadaptors的一個數組(對象類型),並且將三個DataSet(全局實例化)中的每一個都設置爲foreach中的塊(如果塊中的ParameterInfo oPI)(其中' NameOfDataSet'將是其中一個數據集)

任何人都可以在完成此功能的方向上給我一點點推動力(或推力?)嗎?我知道我在那裏,但感覺就像我在看什麼。這段代碼編譯沒有錯誤。

+0

+1 - 我一直認爲xxTableAdapter類應該已經實現了一個通用的接口或從一些基類派生。 – 2009-08-05 18:56:22

+0

我認爲SqlDataAdapter中的xxTableAdapter inehrits是從DbDataAdapter繼承的。它也應該實現IDbDataAdapter接口 – 2009-08-07 11:54:47

回答

1

難道你不能把它們當作它們的基類,DbDataAdapter,DataSet和DataTable嗎?

您可以通過DataSet.Tables [「name」]按名稱訪問表。這將返回一個可以傳遞給DbDataAdapters更新方法的DataTable對象。

或者,如果您的TableAdapter更新您的DataSet中的所有表,那麼您可以直接將整個DataSet傳遞給更新方法。

這樣說,我建議你重新考慮使用類型化的數據集,如果你有機會這樣做。根據我的經驗,他們最終成爲維護和使用的麻煩,並發現一般的DataTable,DataSet和DbDataAdapter類可以直接使用起來更容易。

+0

我傾向於同意你的看法。不幸的是我似乎被鎖定使用這些。這是上面的開發者希望我們使用的方向。這似乎比使用直接的SQL和存儲過程更好。 我有一個TableAdaptors達到表。也許我應該找到一種方法來遍歷每個數據集中的所有TableAdaptor,並將數據集傳遞給它。它會更新它知道如何更新的表格,我可以繼續生活嗎? – bdwakefield 2009-08-07 11:47:27

+0

它應該只更新它所知道的表,因此只需遍歷所有表適配器並將數據集傳遞給update方法應該是安全的。我不確定性能會如何... – 2009-08-07 11:55:59

+0

我遇到的另一個大問題是主要開發人員希望我開始更新我的應用程序以使用數據集。對於不使用數據集的應用程序的其他部分,它播放得並不太好。感謝您的輸入。我將嘗試採取這種方法,看看事態如何。 – bdwakefield 2009-08-07 15:19:04

0

你真的想在你的DAL中使用反射嗎?也許像LINQ to SQL或NHibernate這樣的ORM會是一個很好的選擇?

+0

這是.NET 2.0,它是我們必須使用的。沒有計劃(我知道)升級到3.0或3.5。我不熟悉ORM或NHibernate。我不知道現在爲項目添加框架是一個好主意。 – bdwakefield 2009-08-06 22:18:06

2

我一直在使用它。但它需要一些優化。這也會根據數據集中的關係(如果沒有自引用,可以通過對行進行排序來處理,但爲了簡單起見,我不在這裏發佈)按照正確的順序更新表。

public static void Save(DataSet data, SqlConnection connection) 
    { 
     /// Dictionary for associating adapters to tables. 
     Dictionary<DataTable, SqlDataAdapter> adapters = new Dictionary<DataTable, SqlDataAdapter>(); 

     foreach (DataTable table in data.Tables) 
     { 
      /// Find the table adapter using Reflection. 
      Type adapterType = GetTableAdapterType(table); 
      SqlDataAdapter adapter = SetupTableAdapter(adapterType, connection, validityEnd); 
      adapters.Add(table, adapter); 
     } 

     /// Save the data. 
     Save(data, adapters); 
    } 

    static Type GetTableAdapterType(DataTable table) 
    { 
     /// Find the adapter type for the table using the namespace conventions generated by dataset code generator. 
     string nameSpace = table.GetType().Namespace; 
     string adapterTypeName = nameSpace + "." + table.DataSet.DataSetName + "TableAdapters." + table.TableName + "TableAdapter"; 
     Type adapterType = Type.GetType(adapterTypeName); 
     return adapterType; 
    } 

    static SqlDataAdapter SetupTableAdapter(Type adapterType, SqlConnection connection) 
    { 
     /// Set connection to TableAdapter and extract SqlDataAdapter (which is private anyway). 
     object adapterObj = Activator.CreateInstance(adapterType); 
     SqlDataAdapter sqlAdapter = (SqlDataAdapter)GetPropertyValue(adapterType, adapterObj, "Adapter"); 
     SetPropertyValue(adapterType, adapterObj, "Connection", connection); 

     return sqlAdapter; 
    } 

    static object GetPropertyValue(Type type, object instance, string propertyName) 
    { 
     return type.GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.Instance).GetValue(instance, null); 
    } 

    static void SetPropertyValue(Type type, object instance, string propertyName, object propertyValue) 
    { 
     type.GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.Instance).SetValue(instance, propertyValue, null); 
    } 

    static void Save(DataSet data, Dictionary<DataTable, SqlDataAdapter> adapters) 
    { 
     if (data == null) 
      throw new ArgumentNullException("data"); 

     if (adapters == null) 
      throw new ArgumentNullException("adapters"); 

     Dictionary<DataTable, bool> procesedTables = new Dictionary<DataTable, bool>(); 
     List<DataTable> sortedTables = new List<DataTable>(); 

     while (true) 
     { 
      DataTable rootTable = GetRootTable(data, procesedTables); 
      if (rootTable == null) 
       break; 

      sortedTables.Add(rootTable); 
     } 

     /// Updating Deleted rows in Child -> Parent order. 
     for (int i = sortedTables.Count - 1; i >= 0; i--) 
     { 
      Update(adapters, sortedTables[i], DataViewRowState.Deleted); 
     } 

     /// Updating Added/Modified rows in Parent -> Child order. 
     for (int i = 0; i < sortedTables.Count; i++) 
     { 
      Update(adapters, sortedTables[i], DataViewRowState.Added | DataViewRowState.ModifiedCurrent); 
     } 
    } 

    static void Update(Dictionary<DataTable, SqlDataAdapter> adapters, DataTable table, DataViewRowState states) 
    { 
     SqlDataAdapter adapter = null; 

     if (adapters.ContainsKey(table)) 
      adapter = adapters[table]; 

     if (adapter != null) 
     { 
      DataRow[] rowsToUpdate = table.Select("", "", states); 

      if (rowsToUpdate.Length > 0) 
       adapter.Update(rowsToUpdate); 
     } 
    } 

    static DataTable GetRootTable(DataSet data, Dictionary<DataTable, bool> procesedTables) 
    { 
     foreach (DataTable table in data.Tables) 
     { 
      if (!procesedTables.ContainsKey(table)) 
      { 
       if (IsRootTable(table, procesedTables)) 
       { 
        procesedTables.Add(table, false); 
        return table; 
       } 
      } 
     } 

     return null; 
    } 

    static bool IsRootTable(DataTable table, Dictionary<DataTable, bool> procesedTables) 
    { 
     foreach (DataRelation relation in table.ParentRelations) 
     { 
      DataTable parentTable = relation.ParentTable; 
      if (parentTable != table && !procesedTables.ContainsKey(parentTable)) 
       return false; 
     } 

     return true; 
    }