【问题标题】:Generic DataTable & TableAdaptor updates with Reflection (C#)使用反射 (C#) 更新通用 DataTable 和 TableAdaptor
【发布时间】:2009-08-05 18:06:01
【问题描述】:

我的应用程序中有几个强类型数据集。编写更新数据的方法变得乏味,因为每个方法都有多个表。我想创建一个可以轻松更新所有表的通用函数。我不介意是否必须为每个 DataSet 创建其中一个,但如果一个函数可以处理所有这些,那就太棒了!

将有任意数量的新记录、更新记录或删除记录,并且应正确标记每一行。这个函数应该只是处理实际的保存。这是我目前所拥有的:

    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;

我已经从另一个开发人员在不同应用程序中的另一段代码中改编了这个。到目前为止的主要区别是他传入了一个数据适配器数组(对象类型),并将三个数据集(全局实例化)中的每一个都设置为单独的 if 块内的 foreach(oParamaterInfoArray 中的 ParameterInfo oPI)块(其中我的 ' NameOfDataSet' 将是数据集之一)

任何人都可以在完成这个功能的方向上给我一点推动(或推一下?)吗?我知道我就在那儿,但感觉就像我在寻找某些东西。这段代码编译没有错误。

【问题讨论】:

  • +1 -- 我一直认为 xxTableAdapter 类应该实现了一个通用接口或从某个基类派生。
  • 我认为 xxTableAdapter 继承自 SqlDataAdapter 并继承自 DbDataAdapter。它还应该实现 IDbDataAdapter 接口

标签: c# reflection datatable generics tableadapter


【解决方案1】:

我一直在用这个。不过,它需要一些优化。这还负责根据数据集中的关系以正确的顺序更新表(如果没有自引用,可以通过对行进行排序来处理,但为简单起见,我不在这里发布)。

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

【讨论】:

    【解决方案2】:

    你不能把它们当作它们的基类,DbDataAdapter、DataSet 和 DataTable 吗?

    您可以通过执行 DataSet.Tables["name"] 来按名称访问表。这将返回一个 DataTable 对象,您可以将其传递给 DbDataAdapters 更新方法。

    或者,如果您的 TableAdapter 更新了 DataSet 中的所有表,那么您可以将整个 DataSet 直接传递给 update 方法。

    话虽如此,如果有机会,我建议您重新考虑使用类型化数据集。根据我的经验,它们最终会成为维护和使用的麻烦,并且发现通用 DataTable、DataSet 和 DbDataAdapter 类更容易直接使用。

    【讨论】:

    • 我倾向于同意你的观点。不幸的是,我似乎被锁定在使用这些。这是我上面的开发人员希望我们使用的方向。它似乎比直接使用 SQL 和存储过程更好。我有一个用于到达表的 TableAdaptors。也许我应该找到一种方法来遍历每个数据集中的所有 TableAdaptor,然后将数据集传递给它。它会更新它知道如何更新的表,我可以继续生活吗?
    • 它应该只更新它知道的表,所以只遍历所有表适配器并将数据集传递给更新方法应该是安全的。我不确定性能会如何......
    • 我遇到的另一个大问题是首席开发人员希望我开始更新我的应用程序以使用数据集。它与不使用数据集的应用程序的其他部分配合得不太好。感谢您的输入。我将尝试采用这种方法,看看情况如何。
    【解决方案3】:

    您真的希望在 DAL 中大量使用反射吗?也许像 LINQ to SQL 或 NHibernate 这样的 ORM 会是一个不错的选择?

    【讨论】:

    • 这是 .NET 2.0,我们必须使用它。目前还没有升级到 3.0 或 3.5 的计划(据我所知)。我不熟悉 ORM 或 NHibernate。我不知道现在给项目添加框架是个好主意。
    猜你喜欢
    • 1970-01-01
    • 2012-04-27
    • 1970-01-01
    • 1970-01-01
    • 2021-09-30
    • 1970-01-01
    • 2013-01-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多