使用DataSet的更有效方法

时间:2009-08-13 16:46:32

标签: c# .net winforms refactoring dataset

作为更新过程的一部分,我在每个Form上重复了以下代码。加载页面后,BLL会返回DataSet,请说

_personInfo = ConnectBLL.BLL.Person.GetPerson(personID);

我将DataSet存储在Form级别变量中,然后我在验证/更新过程中使用该变量来检查更改。我一次传递一行(虽然从来没有多于一行)到Function,它接受​​一个控件中的值并将其与{{{}中相应的列值进行比较1}}。如果它发现它不同,则将该列设置为新值,并将名称添加到已更改内容的DataSet

List

我想要得到的答案是,这真的是最有效的解决方法吗?

如果没有别的我想创建一个函数进行比较而不是重复30次(每个表单各不相同)但我不能完全弄明白。我想也许我可以使用row []。ItemArray但只有值。我必须提前知道这些物品的订单和库存不会改变....

我是否遗漏了在 CRUD应用中使用 DataSet / DataTables 的明显内容?


juliandewitt's post below is fantastic!

我现在需要一些关于如何在上面使用它的方向。任何人都可以指向我的链接将不胜感激。如果你能发布一个例子,那就更好了。

使用像这样的DataRows有什么缺点吗?

3 个答案:

答案 0 :(得分:7)

看起来你正在做大量的手工劳动,可以通过将控件直接数据绑定到DataSet / Table来缓解。数据绑定将您的数据源(在本例中为您的数据集/表)与您的UI联系在一起。当UI中的值发生变化时,它将更新数据源。

DataBinding是 BIG 主题,需要进行研究和测试。有一些关于数据绑定到DataTable / Set的问题(行更改在当前行更改之前不会被提交,这在您一次只处理一行的情况下很烦人 - 但是有解决方法)。 / p>

<强>重述: 另一件需要考虑的事情是使用业务对象来表示集/表中的数据。 ORM(对象关系映射器)可以为您处理这个问题,但它们是庞大且功能强大的框架,不容易掌握。这与在UI层使用DataSet的/ Tables完全不同,并且更适用于面向对象的编程。 DataSets和Tables非常适合处理表格数据,但它们不适合使用实体。例如,您将使用 IsHispanic IsCitizen rahtner等属性来处理 Person 对象的实例,而不是基本上对照表中的单元格(没有更多* myPersonTable [0] [“HispanicOriginFlag”] ....)。

进一步:与您的问题无关,但与围绕ADO.NET的CRUD操作相关:熟悉DataTable / DataSet中内置的状态跟踪是值得的。 ADO.NET中有许多内容可以帮助使这些应用程序易于粘合在一起,这样可以清理像你所显示的代码。

与往常一样,RAD工具需要权衡放弃对生产力的控制 - 但是在不理解它们的情况下将它们写下来,可以保证您可以花时间编写像您所展示的代码。

更多:当您发现将Visual Studio的DataSet生成器与DataTables的内置rowstate跟踪结合使用时,要进一步构建我之前的 Further ,对DataSet的更改跟踪可以很容易地在很短的时间内编写完整的CRUD系统。

以下是对所涉及的一些步骤的快速破解:

  1. 建立数据库架构
  2. 在Visual Studio中,将新的DataSet项添加到项目
  3. 查找服务器资源管理器(在视图下)
  4. 将SQL Server添加为数据连接
  5. 将您的表/存储过程/视图拖到DataSet的设计器中。
  6. 右键单击Visual Studio为您生成的“TableAdapter”;转到配置
  7. 配置DataSet的CRUD命令(选择,插入,更新,删除命令)
  8. 您已经创建了强类型数据集。 DataSet将包含以用于生成DataSet的表/视图/存储过程命名的DataTable属性。该Table属性将包含强类型行,它允许您将该行中的单元格作为属性而不是对象数组中的无类型项目进行访问。

    因此,如果您已经生成了一个名为 MyDbTables 的新DataSet,其中包含一个名为 tblCustomer 的表,其中包含一些列,例如 CustomerId 姓名等等......然后你可以像这样使用它:

    这是各种各样的例子,展示了一些用于CRUD工作的常用方法 - 查看方法,特别是TableAdapter类

        public void MyDtDemo()
        {
            // A TableAdapter is used to perform the CRUD operations to sync the DataSet/Table and Database
            var myTa = new ClassLibrary4.MyDbTablesTableAdapters.tblCustomersTableAdapter();
            var myDataSet = new MyDbTables();
    
            // 'Fill' will execute the TableAdapter's SELECT command to populate the DataTable
            myTa.Fill(myDataSet.tblCustomers);
    
            // Create a new Customer, and add him to the tblCustomers table
            var newCustomer = myDataSet.tblCustomers.NewtblCustomersRow();
            newCustomer.Name = "John Smith";
            myDataSet.tblCustomers.AddtblCustomersRow(newCustomer);
    
            // Show the pending changes in the DataTable
            var myTableChanges = myDataSet.tblCustomers.GetChanges();
    
            // Or get the changes by change-state
            var myNewCustomers = myDataSet.tblCustomers.GetChanges(System.Data.DataRowState.Added);
    
            // Cancel the changes (if you don't want to commit them)
            myDataSet.tblCustomers.RejectChanges();
    
            // - Or Commit them back to the Database using the TableAdapter again
            myTa.Update(myDataSet);
        }
    

    另外,请注意DataSet和DataTables的RejectChanges()和AcceptChanges()方法。它们实质上告诉您的数据集它没有任何更改(通过拒绝所有更改,或者“提交”所有更改),但要注意调用AcceptChanges()然后尝试进行更新将无效 - DataSet已丢失跟踪任何更改并假设它是数据库的准确反映。

    甚至更多!这是您的示例的重新设计版本,显示了一些rowstate跟踪功能,假设您已按照我的步骤创建强类型的DataSet / Tables / Rows

        public void CheckRows()
        {
           MyPersonDS tmpPersonDS = new MyPersonDS();
    
            // Load Person info
           using (var tmpPersonDT = tmpPersonDS.PersonDT)
           {
               foreach (MyPersonRow row in tmpPersonDT.Rows)
               {
                   CheckPersonData(row);
               }
           }
    
        }
    
        public void CheckPersonData(MyPersonRow row)
        {
            // If DataBinding is used, then show if the row is unchanged / modified / new...
            System.Diagnostics.Debug.WriteLine("Row State: " + row.RowState.ToString());
    
            System.Diagnostics.Debug.WriteLine("Row Changes:");
            System.Diagnostics.Debug.WriteLine(BuildRowChangeSummary(row));
    
            // If not DataBound then update the strongly-types Row properties
            row.ResidencyCountyID = lkuResidencyCountyId.EditValue;
    
    
        }
    
        public string BuildRowChangeSummary(DataRow row)
        {
            System.Text.StringBuilder result = new System.Text.StringBuilder();
    
            int rowColumnCount = row.Table.Columns.Count;
            for (int index = 0; index < rowColumnCount; ++index)
            {
                result.Append(string.Format("Original value of {0}: {1}\r\n", row.Table.Columns[index].ColumnName, row[index, DataRowVersion.Original]));
                result.Append(string.Format("Current  value of {0}: {1}\r\n", row.Table.Columns[index].ColumnName, row[index, DataRowVersion.Current]));
    
                if (index < rowColumnCount - 1) { result.Append("\r\n"); }
            }
    
            return result.ToString();
        }
    

答案 1 :(得分:2)

如果对映射到数据集列名称的属性使用一致的命名约定,则反射将使单个可重用方法成为可能。但是,您需要对其进行测试以确保它不会导致性能问题。

要执行此操作,请从表中循环显示Columns集合。然后,对于每列,使用反射来查找与行进行比较的对象上的“匹配”属性。 (您将需要关注从obj.GetType()返回的PropertyInfo类.GetProperties(...)。)

答案 2 :(得分:2)

数据行也会自动跟踪变化。

DataRow _personInfo = ConnectBLL.BLL.Person.GetPerson(personID);  
// _personInfo.RowState = DataRowState.Unchanged
_personInfo["columnName"] = "value";
_personInfo["columnName2"] = "value2";
_personInfo.EndEdit();
// _personInfo.RowState = DataRowState.Modified

现在,您可以通过询问rowstate并按如下方式检查值来获取更改的值

var org = fRow["columnName", DataRowVersion.Original]; 
var new = fRow["columnName",DataRowVersion.Current];

要检测更改,您还可以收听columnchanged事件。

fTable.ColumnChanged += new DataColumnChangeEventHandler(delegate(object sender, DataColumnChangeEventArgs e)
{
   Console.WriteLine(e.Column.ColumnName);
}
);