数据集丢失并在 C# 中合并

发布于 2024-08-17 22:21:55 字数 5553 浏览 7 评论 0 原文

最新编辑!!!

请...我已经对这段代码进行了多次排列。我正在尝试从数据库(SQL 服务器)中获取一些某些相关记录并导出到 XML(这似乎有效!),并将它们带到该数据库的断开连接副本,并将它们导入到该数据库,按主数据库合并它们键(如果键存在则更新,如果不存在则插入)。

数据库中有很多表,我想要与已更改的某个实体列表相关的所有表。我很早就发现我无法使用联接执行大型复杂查询来获取我想要填充导出数据集的所有列,因为我丢失了所有表结构。我还让 Visual Studio 2005 数据集设计器创建了一个类型化数据集,我不确定是否需要这样做,如果不需要,请告诉我。

下面是我将数据导出到 xml 的方法:



public void exportData(string filename, List sxOrgs) {

    MyGeneratedDataSet ds = new MyGeneratedDataSet();
    SqlDataAdapter adapter = new SqlDataAdapter();
    String query;
    String orgList = "(";
    //create the string query list of sxOrgs

    foreach (String sx in sxOrgs)
    {
        orgList += "'" + sx + "', ";
    }

    orgList = orgList.Remove(orgList.Length - 2);
    orgList += ")";

    try
        {

        //tblOrganization
        query = "select * from tblOrganization where tblOrganization.sxOrganization in " 
             + orgList;
        adapter.SelectCommand = new SqlCommand(query, Connectivity.Connection());
        adapter.Fill(ds.tblOrganization);

        //tblCategory
        query = "select * from tblCategory where sxCategory in " +
            "(select sxCategory from lnkOrganizationCategory " +
            "where lnkOrganizationCategory.sxOrganization in " +
            orgList + ")";
        adapter.SelectCommand = new SqlCommand(query, Connectivity.Connection());
        adapter.Fill(ds.tblCategory);

        //lnkOrganizationCategory
        query = "select * from lnkOrganizationCategory where sxOrganization in " + orgList;
            adapter.SelectCommand = new SqlCommand(query, Connectivity.Connection());
            adapter.Fill(ds.lnkOrganizationCategory);

        //tblContact
        query = "select * from tblContact where sxContact in " +
            "(select sxContact from lnkOrganizationContact " +
            "where lnkOrganizationContact.sxOrganization in " +
            orgList + ")";
        adapter.SelectCommand = new SqlCommand(query, Connectivity.Connection());
        adapter.Fill(ds.tblContact);

        //lnkOrganizationContact
        query = "select * from lnkOrganizationContact where lnkOrganizationContact.sxOrganization in " + orgList;
        adapter.SelectCommand = new SqlCommand(query, Connectivity.Connection());
        adapter.Fill(ds.lnkOrganizationContact);
    } catch(Exception ex) {
        Debug.WriteLine(ex.Message);
    }

    ds.WriteXml(filename, XmlWriteMode.IgnoreSchema);
}

如您所见,我一遍又一遍地重复使用同一个 TableAdapeter,最后编写的 XML 看起来很好,每个都有一个标签表,并在其中为每个字段添加一个标记,这正是我想要的,并且能够将其合并回来。这是导入代码:



//reads data from an xml file and merges it into existing db
public static void ImportData(string data)
{
    try
    {

    MyGeneratedDataSet newData = new MyGeneratedDataSet();

    StreamWriter sw = new StreamWriter("newdata.xml", false);
    Debug.WriteLine(data);
    sw.Write(data);
    sw.Close();
    XmlTextReader reader = new XmlTextReader(new MemoryStream(ASCIIEncoding.Default.GetBytes(data)));
    newData.ReadXml("newData.xml");

    MyGeneratedDataSet currentData = new MyGeneratedDataSet();

    //tblOrganization
    SqlDataAdapter tblOrganizationDataAdapter = new SqlDataAdapter("select * from tblOrganization", Connectivity.Connection());
    SqlCommandBuilder tblOrganizationCommandBuilder = new SqlCommandBuilder(tblOrganizationDataAdapter);
    tblOrganizationDataAdapter.Fill(currentData, "tblOrganization");

    //tblContact
    SqlDataAdapter tblContactDataAdapter = new SqlDataAdapter("select * from tblContact", Connectivity.Connection());
    SqlCommandBuilder tblContactCommandBuilder = new SqlCommandBuilder(tblContactDataAdapter);
    tblContactDataAdapter.Fill(currentData, "tblContact");

    //tblCategory
    SqlDataAdapter tblCategoryDataAdapter = new SqlDataAdapter("select * from tblCategory", Connectivity.Connection());
    SqlCommandBuilder tblCategoryCommandBuilder = new SqlCommandBuilder(tblCategoryDataAdapter);
    tblCategoryDataAdapter.Fill(currentData, "tblCategory");

    //lnkOrganizationCategory
    SqlDataAdapter lnkOrganizationCategoryDataAdapter = new SqlDataAdapter("select * from lnkOrganizationCategory", Connectivity.Connection());
    SqlCommandBuilder lnkOrganizationCategoryCommandBuilder = new SqlCommandBuilder(lnkOrganizationCategoryDataAdapter);
    lnkOrganizationCategoryDataAdapter.Fill(currentData, "lnkOrganizationCategory");

    //lnkOrganizationContact
    SqlDataAdapter lnkOrganizationContactDataAdapter = new SqlDataAdapter("select * from lnkOrganizationContact", Connectivity.Connection());
    SqlCommandBuilder lnkOrganizationContactCommandBuilder = new SqlCommandBuilder(lnkOrganizationContactDataAdapter);
    lnkOrganizationContactDataAdapter.Fill(currentData, "lnkOrganizationContact");

    Debug.WriteLine(tblOrganizationDataAdapter.SelectCommand.CommandText);
    Debug.WriteLine(tblOrganizationDataAdapter.UpdateCommand.CommandText);

    currentData.Merge(newData);

    tblOrganizationDataAdapter.Update(currentData);
    tblContactDataAdapter.Update(currentData);
    tblCategoryDataAdapter.Update(currentData);
    lnkOrganizationCategoryDataAdapter.Update(currentData);
    lnkOrganizationContactDataAdapter.Update(currentData);


    } catch (Exception ex) {
        Debug.WriteLine(ex.Message);
    }

}

目前,导入函数末尾附近的 Debug.WriteLine 显示tblOrganizationTableAdapter 的 UpdateCommand 为空。视觉设计师告诉我,它创建它是为了,尽管如果我所要做的就是创建它,当然,我会这样做,但我现在已经重写了很多次(而且还有比这更多的表) ,我还是不明白发生了什么事。我应该怎么做?

太感谢了! Joshua


这段代码几乎可以工作。现在它不再失败了,但是,我最终得到了所有重复的行,而不是通过主键比较进行更新!

NEWEST EDIT!!!

PLEASE... I have been through many permutations of this code. I am attempting to take some certain related records from a database (SQL server) and export to XML (which seems to work!), and take them to a disconnected copy of that database, and import them to that database, merging them by primary key (updating if the key exists and inserting if it doesn't).

There are many tables in the database, and I want all the tables that relate to a certain list of entities that have been changed. I figured out early on that I couldn't do a large complicated query with joins to get all the columns I wanted to fill my export DataSet, because I lost all the table structure. I also had the Visual Studio 2005 DataSet designer create a typed dataset, which I'm not sure I need to do, and please tell me if I shouldn't.

Here is what I'm doing to export the data to xml:



public void exportData(string filename, List sxOrgs) {

    MyGeneratedDataSet ds = new MyGeneratedDataSet();
    SqlDataAdapter adapter = new SqlDataAdapter();
    String query;
    String orgList = "(";
    //create the string query list of sxOrgs

    foreach (String sx in sxOrgs)
    {
        orgList += "'" + sx + "', ";
    }

    orgList = orgList.Remove(orgList.Length - 2);
    orgList += ")";

    try
        {

        //tblOrganization
        query = "select * from tblOrganization where tblOrganization.sxOrganization in " 
             + orgList;
        adapter.SelectCommand = new SqlCommand(query, Connectivity.Connection());
        adapter.Fill(ds.tblOrganization);

        //tblCategory
        query = "select * from tblCategory where sxCategory in " +
            "(select sxCategory from lnkOrganizationCategory " +
            "where lnkOrganizationCategory.sxOrganization in " +
            orgList + ")";
        adapter.SelectCommand = new SqlCommand(query, Connectivity.Connection());
        adapter.Fill(ds.tblCategory);

        //lnkOrganizationCategory
        query = "select * from lnkOrganizationCategory where sxOrganization in " + orgList;
            adapter.SelectCommand = new SqlCommand(query, Connectivity.Connection());
            adapter.Fill(ds.lnkOrganizationCategory);

        //tblContact
        query = "select * from tblContact where sxContact in " +
            "(select sxContact from lnkOrganizationContact " +
            "where lnkOrganizationContact.sxOrganization in " +
            orgList + ")";
        adapter.SelectCommand = new SqlCommand(query, Connectivity.Connection());
        adapter.Fill(ds.tblContact);

        //lnkOrganizationContact
        query = "select * from lnkOrganizationContact where lnkOrganizationContact.sxOrganization in " + orgList;
        adapter.SelectCommand = new SqlCommand(query, Connectivity.Connection());
        adapter.Fill(ds.lnkOrganizationContact);
    } catch(Exception ex) {
        Debug.WriteLine(ex.Message);
    }

    ds.WriteXml(filename, XmlWriteMode.IgnoreSchema);
}

As you can see, I'm reusing the same TableAdapeter over and over and the XML that is written at the end seems to look fine and nice, having a tag for each table, and within it a tag for each field, exactly what I want, and to be able to merge it back in. Here is the import code:



//reads data from an xml file and merges it into existing db
public static void ImportData(string data)
{
    try
    {

    MyGeneratedDataSet newData = new MyGeneratedDataSet();

    StreamWriter sw = new StreamWriter("newdata.xml", false);
    Debug.WriteLine(data);
    sw.Write(data);
    sw.Close();
    XmlTextReader reader = new XmlTextReader(new MemoryStream(ASCIIEncoding.Default.GetBytes(data)));
    newData.ReadXml("newData.xml");

    MyGeneratedDataSet currentData = new MyGeneratedDataSet();

    //tblOrganization
    SqlDataAdapter tblOrganizationDataAdapter = new SqlDataAdapter("select * from tblOrganization", Connectivity.Connection());
    SqlCommandBuilder tblOrganizationCommandBuilder = new SqlCommandBuilder(tblOrganizationDataAdapter);
    tblOrganizationDataAdapter.Fill(currentData, "tblOrganization");

    //tblContact
    SqlDataAdapter tblContactDataAdapter = new SqlDataAdapter("select * from tblContact", Connectivity.Connection());
    SqlCommandBuilder tblContactCommandBuilder = new SqlCommandBuilder(tblContactDataAdapter);
    tblContactDataAdapter.Fill(currentData, "tblContact");

    //tblCategory
    SqlDataAdapter tblCategoryDataAdapter = new SqlDataAdapter("select * from tblCategory", Connectivity.Connection());
    SqlCommandBuilder tblCategoryCommandBuilder = new SqlCommandBuilder(tblCategoryDataAdapter);
    tblCategoryDataAdapter.Fill(currentData, "tblCategory");

    //lnkOrganizationCategory
    SqlDataAdapter lnkOrganizationCategoryDataAdapter = new SqlDataAdapter("select * from lnkOrganizationCategory", Connectivity.Connection());
    SqlCommandBuilder lnkOrganizationCategoryCommandBuilder = new SqlCommandBuilder(lnkOrganizationCategoryDataAdapter);
    lnkOrganizationCategoryDataAdapter.Fill(currentData, "lnkOrganizationCategory");

    //lnkOrganizationContact
    SqlDataAdapter lnkOrganizationContactDataAdapter = new SqlDataAdapter("select * from lnkOrganizationContact", Connectivity.Connection());
    SqlCommandBuilder lnkOrganizationContactCommandBuilder = new SqlCommandBuilder(lnkOrganizationContactDataAdapter);
    lnkOrganizationContactDataAdapter.Fill(currentData, "lnkOrganizationContact");

    Debug.WriteLine(tblOrganizationDataAdapter.SelectCommand.CommandText);
    Debug.WriteLine(tblOrganizationDataAdapter.UpdateCommand.CommandText);

    currentData.Merge(newData);

    tblOrganizationDataAdapter.Update(currentData);
    tblContactDataAdapter.Update(currentData);
    tblCategoryDataAdapter.Update(currentData);
    lnkOrganizationCategoryDataAdapter.Update(currentData);
    lnkOrganizationContactDataAdapter.Update(currentData);


    } catch (Exception ex) {
        Debug.WriteLine(ex.Message);
    }

}

At the moment, the Debug.WriteLine near the end of the import function shows that the UpdateCommand of the tblOrganizationTableAdapter is null. The visual designer had told me that it created that for, though if all I have to do is create it, sure, I'll do that, but I've rewritten this so many times now (and there's lots more tables than this), and I still don't understand what's going on. How SHOULD I be doing this?!

THANK YOU SO MUCH!
Joshua


This code almost works. It now doesn't fail anymore, however, I end up with all duplicate rows, instead of updating via the primary key comparison!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

辞慾 2024-08-24 22:21:55

你正在做的事情听起来是对的。我不确定您的确切问题是什么,但这里是流程的细分:

  1. 将新数据加载到数据集中(就像您所做的那样)
  2. 从数据库获取当前数据到数据集中 (就像您所做的那样)
  3. 调用 CurrentData.Merge(NewData) (就像您所做的那样)
  4. 将 CurrentData 保存回数据库(我不参见这部分)

当您执行步骤 #4 时,表适配器会查看 DataSet 中的每个表并找出哪些行已更改。它之所以知道,是因为每个 DataTable 中的每个 DataRow 都会将其 DataRowState 设置为 AddedModifiedMerge(),导致 Deleted。然后,表适配器在底层数据库中执行请求的更改,并将 DataRowDataRowState 设置为 UnchangedDataRow 的情况除外) >当然,已删除)。当此过程完成时,底层数据库应该包含 NewData 数据集包含的所有更改。

What you are doing sounds right. I'm not sure what your exact problem is, but here is a breakdown of the flow:

  1. Load new data into a DataSet (like you've done)
  2. Get current data from database into DataSet (like you've done)
  3. Call CurrentData.Merge(NewData) (like you've done)
  4. Save the CurrentData back to the database (I don't see this part)

When you perform step #4, the table adapters look at each table in the DataSet and find out which rows have changed. It knows because each DataRow in each DataTable will have its DataRowState set to Added, Modified or Deleted as a result of your call to Merge(). The table adapter then performs the requested change in the underlying database and sets the DataRowState to Unchanged for the DataRow (except in the case of Deleted, of course). When this process completes, the underlying database should have all the changes in it that the NewData dataset contained.

野生奥特曼 2024-08-24 22:21:55

Blah:

  • 从 xml 行加载数据集。
  • 确保每行的 RowState 标志都是正确的:
    • 未更改、修改、添加或删除
  • 不要调用 AcceptChanges(),它将每行的行状态设置为“未更改”并删除标记为“已删除”() 的行。这是由内部完成的...

代码:

using (SqlDataAdapter dap = new SqlDataAdapater(myConnection, "SELECT * FROM MyTable"))
    dap.Update(myDataTable)

Blah:

  • Load your dataset from the xml rows.
  • Make sure the RowState flag is correct for each row:
    • Unchanged, Modified, Added, or Deleted
  • Don't call AcceptChanges(), it sets the row sate for every row to Unchanged and removes rows marked Deleted(). This is done internally by...

Code:

using (SqlDataAdapter dap = new SqlDataAdapater(myConnection, "SELECT * FROM MyTable"))
    dap.Update(myDataTable)
熊抱啵儿 2024-08-24 22:21:55

update 需要在某个时刻被调用:

adapter.Update(currentData, "table1")

一般来说,直接在 sql 中合并 2 个表可能更容易,但是您的应用程序可能需要处理 xml 文件..

使用合并/更新的示例:

http://msdn.microsoft.com/en-us/library/aa325628%28VS.71 %29.aspx

在 t-sql 中,您可以使用 MERGE 在一条语句中执行此操作:

http://technet.microsoft.com/en-us/library/bb510625.aspx

调整它以适应您想要更改/更新行时的条件

update would need to be called at some point:

adapter.Update(currentData, "table1")

in general its probably easier to merge 2 tables directly in sql, but your app may need to process xml files..

examples of using Merge/Update:

http://msdn.microsoft.com/en-us/library/aa325628%28VS.71%29.aspx

in t-sql, you can do this in one statement with MERGE:

http://technet.microsoft.com/en-us/library/bb510625.aspx

tweak it to suit the conditions when you want the row changed / updated

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文