Потерял с DataSets и слияния в C#
НОВОЕ РЕДАКТИРОВАНИЕ!!!
ПОЖАЛУЙСТА... Я прошел через много перестановок этого кода. Я пытаюсь взять некоторые определенные связанные записи из базы данных (сервер SQL) и экспортировать в XML (что, похоже, работает!), Перенести их в отключенную копию этой базы данных и импортировать их в эту базу данных, объединяя их по основной ключ (обновление, если ключ существует, и вставка, если его нет).
В базе данных много таблиц, и мне нужны все таблицы, которые относятся к определенному списку сущностей, которые были изменены. Ранее я понял, что не могу выполнить большой сложный запрос с объединениями, чтобы получить все столбцы, которые я хотел заполнить в своем экспортном DataSet, потому что я потерял всю структуру таблицы. У меня также был дизайнер Visual Studio 2005 DataSet, который создал типизированный набор данных, что я не уверен, что мне нужно делать, и, пожалуйста, скажите мне, если я не должен.
Вот что я делаю, чтобы экспортировать данные в 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 в конце функции импорта показывает, что UpdateCommand объекта tblOrganizationTableAdapter имеет значение null. Визуальный дизайнер сказал мне, что он создал это для, хотя, если все, что мне нужно сделать, это создать, конечно, я сделаю это, но я переписывал это так много раз (и таблиц намного больше, чем это) и я до сих пор не понимаю, что происходит. Как я должен это делать?!
СПАСИБО ОГРОМНОЕ! Джошуа
Этот код почти работает. Теперь это больше не дает сбоя, однако я получаю все дублирующиеся строки вместо обновления через сравнение по первичному ключу!
3 ответа
То, что вы делаете, звучит правильно. Я не уверен, в чем именно заключается ваша проблема, но вот разбивка потока:
- Загрузите новые данные в DataSet (как вы сделали)
- Получить текущие данные из базы данных в DataSet (как вы сделали)
- Вызов CurrentData.Merge (NewData) (как вы сделали)
- Сохранить CurrentData обратно в базу данных (я не вижу эту часть)
При выполнении шага № 4 адаптеры таблиц просматривают каждую таблицу в DataSet
и узнайте, какие строки изменились. Это знает, потому что каждый DataRow
в каждом DataTable
будет иметь DataRowState
установлен в Added
, Modified
или же Deleted
в результате вашего звонка Merge()
, Затем адаптер таблицы выполняет запрошенное изменение в базовой базе данных и устанавливает DataRowState
в Unchanged
для DataRow
(кроме случая Deleted
, конечно). Когда этот процесс завершится, базовая база данных должна иметь все изменения, содержащиеся в наборе данных NewData.
Л:
- Загрузите ваш набор данных из строк XML.
- Убедитесь, что флаг RowState правильный для каждой строки:
- Не изменены, изменены, добавлены или удалены
- Не вызывайте AcceptChanges(), он устанавливает для каждой строки значение "Не изменено" и удаляет строки, помеченные как "Deleted()". Это делается внутренне...
Код:
using (SqlDataAdapter dap = new SqlDataAdapater(myConnection, "SELECT * FROM MyTable"))
dap.Update(myDataTable)
Обновление должно быть вызвано в какой-то момент:
adapter.Update(currentData, "table1")
в общем, вероятно, проще объединить 2 таблицы непосредственно в SQL, но вашему приложению может потребоваться обработка XML-файлов.
Примеры использования Merge / Update:
http://msdn.microsoft.com/en-us/library/aa325628%28VS.71%29.aspx
в t-sql вы можете сделать это одним оператором с помощью MERGE:
http://technet.microsoft.com/en-us/library/bb510625.aspx
настроить его в соответствии с условиями, когда вы хотите, чтобы строка была изменена / обновлена