Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Базы данных под .NET > Закешировать в датасет части таблиц


Автор: Pankon 30.1.2008, 18:44
Как закешировать в датасет часть первой таблицы(топ 1000) и соответствующую 
часть  второй таблицы(таблицы связаны по внешнему ключу) используя "один" запрос.

Читал, что что-то подобное можно сделать с помощью OleDbDataAdapter  и "SHAPE ... APPEND .... RELATE ...", но до конца не розабрался :(

Может и без OleDbDataAdapter  это возможно .....



Автор: thomas 30.1.2008, 18:53
Pankon, 
Приветствую.
Если работаем с БД Access то использование OleDbDataAdapter как бы обязательно.

Создаешь соединение, создаешь обьект команды, создаешь на их основе OleDbDataAdapter. Далее выполняешь метод Fill() для OleDbDataAdapter что бы заполнить таблицу в ДатаСет данными из БД.

Цитата

Как закешировать в датасет часть первой таблицы(топ 1000) и соответствующую 
часть  второй таблицы(таблицы связаны по внешнему ключу) используя "один" запрос.

Вся фишка в том что бы написать грамотно sql команду. Раз тебе надо взять данные из двух связанных таблиц используем JOIN , а так же оператор TOP 1000 для соответствующей таблицы.
Если напишешь правильный запрос к БД, то получишь в ДатаСет таблицу с первыми 1000 записями.

Успехов.  smile 

Автор: Pankon 31.1.2008, 11:11
Цитата(thomas @  30.1.2008,  18:53 Найти цитируемый пост)
Если работаем с БД Access
 sorry, забыл сказать MS SQL Server 2000

Цитата(thomas @  30.1.2008,  18:53 Найти цитируемый пост)
Раз тебе надо взять данные из двух связанных таблиц используем JOIN
 JOIN возвращает одну таблицу, а мне нужно две связанные таблицы запихнуть в Dataset

Автор: unicuum 31.1.2008, 13:38
Помимо запросов, ещё такая фича есть:

Fill(DataSet dataSet, int startRecord, int maxRecords, string srcTable);

Заливка начиная с номера записи startRecord и всего maxRecords.

Автор: thomas 31.1.2008, 14:44
Pankon, 
Цитата

MS SQL Server 2000

Значит, используем sqlClient вместо OleDb.
Цитата

мне нужно две связанные таблицы запихнуть в Dataset

так и в чем проблема? В данном случае тебе нужно будет два раза присвоить свойству команд sql-команду, сначала к одной таблице, потом ко второй.
И соответственно два раза вызвать метод Fill() для ДатаАдаптер, что бы сначала создать и заполнить в ДатаСет первую таблицу, а потом и вторую.
Раз тебе нужны первые 1000 записей, то в запросе к соответсвующей таблице используй оператор ТОР. Да и не забудь создать обьект relation между таблицами в ДатаСет.
Усё.

Успехов.  smile 


Автор: Pankon 31.1.2008, 15:00
Цитата(thomas @  31.1.2008,  14:44 Найти цитируемый пост)
Да и не забудь создать обьект relation между таблицами в ДатаСет.
 и тогда из второй таблице получу тольке те записи, которые соответствуют записям из первой таблици(топ 1000)? (правда не знаю  smile )

Автор: unicuum 31.1.2008, 19:48
Цитата(thomas @  31.1.2008,  14:44 Найти цитируемый пост)
Раз тебе нужны первые 1000 записей, то в запросе к соответсвующей таблице используй оператор ТОР. Да и не забудь создать обьект relation между таблицами в ДатаСет.

А как тебе использовать Fill? Вроде не должно тормозить систему, если берутся записи начиная с нулевой.

Код

Me.OleDbDataAdapter1.Fill(dataSet, 0, 1000, "tblTable1")
Me.OleDbDataAdapter1.Fill(dataSet, 0, 1000, "tblTable2")

И потом соответственно ещё Relation добавить. Но оптимальный ли это вариант в целом, то есть вручную всё делать?

Автор: thomas 31.1.2008, 22:20
unicuum, 
Приветствую.
Очень замечательный совет
Код

Me.OleDbDataAdapter1.Fill(dataSet, 0, 1000, "tblTable1")
Me.OleDbDataAdapter1.Fill(dataSet, 0, 1000, "tblTable2")

А кто может гарантировать, что первая тысяча строк второй таблицы имеет какое-то отношение к первой тысяче строк первой таблицы?


Pankon, 
При запросе ко второй таблице без INNER JOIN не обойтись. Потому как тебе надо из второй таблицы получить только те записи, которые имеют отношение к первым 1000 записям первой таблицы. И соответственно не забудь прикрутить оператор ТОР для первой таблицы, ведь тебе надо из второй таблицы получить только те записи, которые относятся к первой тысяче записей первой таблицы.

И уже потом когда в ДатаСет будут созданы и заполнены данными две таблицы, создавай для них обьект relation.

Теперь, надеюсь, все понятно.
Успехов.  smile 

Автор: Pankon 1.2.2008, 11:09
thomas, я понял так, 
первый fill с -
"Select top 1000 key1, * From Table1"

а второй fill с 
"Select * From Table2 inner join INNER JOIN  (SELECT * FROM Table2) t2 ON Table1.key1= t2.key1"

Но это не совсем то, что я хотел.
В первом посте я говорил -  используя "один" запрос для обоих таблиц. 
По нескольким причинам:
1. между первым fill и вторым fill данные в таблицах могут изменится, соответственно, второй fill "вытянет" из второй таблицы уже не "валидные" данные  для закэшированных данных из первой. (сразу скажу, что блокировать таблицы нельзя).

2. нужно оптимизировать обращение к базе данных, поэтому и хотелось вначале закэширивать данные, а потом "обрабатывать".  В нашем же случае - два  fill  -   два запроса к БД - ничего, как мне кажется, не оптимизируют. Кроме того, второй  запрос с JOIN  содержит такой же  "подзапрос" как и первый fill, - два одинаковых запроса к таблице1  smile 
    

Автор: farad 1.2.2008, 14:15
попробуй http://msdn.microsoft.com/library/RUS/cpguide/html/cpconpopulatingdatasetfromdataadapter.asp, тебе понравится

Автор: Pankon 1.2.2008, 14:44
farad, пожалуйста выражайся яснее....

Автор: farad 1.2.2008, 15:02
Цитата(Pankon @  1.2.2008,  14:44 Найти цитируемый пост)
 засаряешь форум...
А что осилить страницу текста по сылке тяжело? Специально для вас адаптированный вариант:
Цитата(MSDN)

В следующем примере с помощью поставщика данных MSDataShape создается сегментированный столбец заказов для каждого заказчика, имеющегося в списке заказчиков. Затем этими данными заполняется объект DataSet.

Код

OleDbConnection nwindConn = new OleDbConnection("Provider=MSDataShape;Data Provider=SQLOLEDB;" +
                                  "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind");

OleDbDataAdapter custDA = new OleDbDataAdapter("SHAPE {SELECT CustomerID, CompanyName FROM Customers} " +
                                      "  APPEND ({SELECT CustomerID, OrderID FROM Orders} AS Orders " +
                                      "  RELATE CustomerID TO CustomerID)", nwindConn);

DataSet custDS = new DataSet();
custDA.Fill(custDS, "Customers");


По завершении работы метода Fill объект DataSet будет содержать две таблицы: Customers и CustomersOrders, где CustomersOrders представляет собой столбец с разделами. В таблицу Customers добавлен дополнительный столбец с именем Orders, а в таблицу CustomersOrders — дополнительный столбец с именем CustomersOrders. Столбец Orders в таблице Customers установлен в режим автоматического приращения. Объект DataRelation с именем CustomersOrders создан на основе добавленных в таблицы столбцов, причем Customers — это родительская таблица.


Автор: Pankon 1.2.2008, 15:14
farad, уже прочитал....
Если бы ты сказал, что речь идет про "SHAPE ... APPEND .... RELATE ..." и ссылку, то было бы все понятней...
Ну да ладно... все равно получай плюс  smile 


ПС. Ха, тебе уже thomas тоже за то же рейтинг поднял ..... Не беда..... будешь иметь два плюса.....

Автор: farad 1.2.2008, 15:33
Цитата(Pankon @  1.2.2008,  14:44 Найти цитируемый пост)
farad, пожалуйста выражайся яснее....
 Согласен, был неконкретен. Учту на будущее. smile  А плюсы я люблю  smile 

Автор: Pankon 1.2.2008, 17:30
Протестировал "SHAPE ... APPEND .... RELATE ..."  на маленьких таблицах - то что надо...

Протестировал на больших таблицах.... результат удручающий....
Причем для первой таблицы сделал топ 1.

Такое ащющение, что вторая таблица вначале ПОЛНОСТьЮ кэшируется на локальной мачине  smile . 
Как покажавает Task-Manager после запуска оперативнай память(~20 мин) забивается до предела, и затем, мое тестовое приложение дает исключение - переполненние опер.памяти
Во время работы тестового приложение нашел в Enterprise Manager процесс для моего коннекта, там стоит "Select top 1 * From Table1;Select * From Table2".

Так резултатов тестов я и не получил   smile 








Автор: unicuum 2.2.2008, 06:04
Цитата(thomas @  31.1.2008,  22:20 Найти цитируемый пост)
А кто может гарантировать, что первая тысяча строк второй таблицы имеет какое-то отношение к первой тысяче строк первой таблицы?

Не в этом дело, я просто показал как неэффективно делать в данном случае зависимости вручную. Кэшировать таблицы по любому будет DataAdapter, в нём есть четыре свойства SelectCommand, InsertCommand, DeleteCommand, UpdateCommand. Их ввели не просто так, а для того чтобы можно было выполнить любой DML-запрос (Data Manipulation Language - Язык Управления Данными), как к целой БД, так и к её отдельным частям. Как правило структура базы данных со всеми зависимостями уже прописана в ней самой, то есть схема уже есть. В следствие чего не важно, хочешь получить всю базу или её часть, разумно использовать схему из базы данных, и менять запросы на выборку, вставку, удаление и обновление.

А вообще, я потому и редко даю в этом топике советы, потому что вопросы задаются не правильно. Надо было написать структуру БД, для чего нужно кэшировать данные, то есть для каких целей это понадобилось и так далее. Гадать же есть в базе схема или нет, есть ли она не в базе предположим, а в отдельном файле или нет, и так далее, это пустая трата времени, а Pankon в данном случае по любому получит не эффективное решение.

Причём при заливке, то есть кэшировании данных в отсоединённые объекты есть свои нюансы, тоже существенно ускоряющие её. То есть важно не просто правильно составить запрос, но и правильно его послать. А учитывая использование MS SQL Server 2000, вариантов будет множество, так как T-SQL довольно мощная штука.

farad, зря ты используешь System.Data.OleDb, вместо System.Data.SqlClient, получаешь лишний уровень абстракции замедляющий работу всей системы, лишаешься многих возможностей MS SQL Server.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)