Допустим, у меня есть огромная таблица заказов, а другая - гораздо большая таблица деталей заказа.
У меня есть DataSet
который заполняется из двух SqlDataAdapter
s. Первый выбирает заказы для указанного клиента. Второй должен выбрать информацию о заказе заказов указанного клиента (которые выбираются первым SqlDataAdapter
). Но я не могу найти способ сделать это элегантно. Когда я добавляю отношения, я получаю сообщение об ошибке: "Это ограничение не может быть включено, поскольку не все значения имеют соответствующие родительские значения".
Я не хочу отключать создание ограничения при создании отношения, я также не хочу выбирать все строки второй таблицы. Есть ли правильный способ сделать это? Или единственный способ создать инструкцию SQL с помощью предложения fe IN
? Теперь, как я понял, не имеет значения, добавляю ли я эту взаимосвязь перед заполнением таблиц или после этого, я получу это сообщение при добавлении отношения после заполнения таблиц или при заполнении второй таблицы в случае, если отношение было добавляется до совокупности данных.
System.Data.DataSet dataSet = new System.Data.DataSet();
String connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
System.Data.SqlClient.SqlConnection dbCon = new System.Data.SqlClient.SqlConnection(connectionString);
System.Data.SqlClient.SqlDataAdapter ordersAdapter = new System.Data.SqlClient.SqlDataAdapter(String.Format("SELECT * FROM dbo.Orders Where CustomerId={0}", customerId), dbCon),
detailsAdapter = new System.Data.SqlClient.SqlDataAdapter("SELECT * FROM dbo.OrderDetails", dbCon); //Perhaps, I should change this to select only the rows needed, or shouldn't specify SQL at all since it should get all the related rows...
try
{
dbCon.Open();
ordersAdapter.Fill(dataSet, "Orders");
detailsAdapter.Fill(dataSet, "OrderDetails");
}
catch (Exception e)
{
Response.Write("Database error: " + e.Message);
}
finally
{
dbCon.Close();
dbCon.Dispose();
}
dataSet.Relations.Add("Orders2Details", dataSet.Tables["Orders"].Columns["Id"], dataSet.Tables["OrderDetails"].Columns["OrderId"]/*, false*/); //I don't want to use this false
Вам необходимо заполнить DetailsAdapter
соответствующими данными заказа для клиента; только тогда вы можете создать связь между ними.
Итак, что-то вроде
SELECT * FROM dbo.OrderDetails INNER JOIN dbo.Orders ON OrderDetails.OrderID =
Orders.OrderID WHERE Orders.CustomerId = ...
Сделаю.
Однако не делайте этого с вашими запросами в реальности. Используйте хранимые процедуры (запрос компилируется на сервере db, поэтому выполняется намного лучше), или, если вы должны использовать встроенный SQL, используйте класс SqlParameter
чтобы избежать SQL-инъекции.
Мне нечего мешать
'1;DROP TABLE Orders;'
как значение для идентификатора клиента, которое я хочу найти, и когда оно добавлено в ваш запрос, оно становится тем, что вы действительно не хотите выполнять.
SqlParameter
s, если входные данные поступают от пользователя ... Я надеялся, что есть хороший способ выполнить этот вид задач, возможно, используя какие-то внутренние колеса dotNet, без всяких хлопот с почерком SQL ...
Where
непригодной для использования.