Re: c# winforms унифицировать обращение к TableAdapter | |
---|---|
AlexSSS Автор Сообщений: 6113 Откуда: Tallinn, Estonia Дата регистрации: 19.09.2005 |
На твоем примере List<adres> adr = db.adres.ToList(); // получаем первоначальный список записей следующая задача - раз в минуту у меня по таймеру подтягиваются все новые и измененные записи с БД получаю список новых и измененных записей List<adres> adrModified = db.adres.where(p=> p.Timestamp > tsTimestamp); // tsTimestamp - это максимальный TimeStamp в локальном списке List<adres> как его засунуть в существующий List<adres> adr с учетом того, что некоторые ID (записи) там уже есть, а некоторые - новые? adr.AddRange(adrModified) не работает (должна ли работать - не знаю, я со списками только начинаю разбираться) |
Re: c# winforms унифицировать обращение к TableAdapter | |
---|---|
Igor Korolyov Сообщений: 34580 Дата регистрации: 28.05.2002 |
Хорошо когда и таблиц в схеме 3 штуки да связей всего две, и это Book, Purchase да Client Да и то "могут быть нюансы". Да, с линкью "надо разбираться". Само по себе понимание в голову из ноосферы не придёт. Я бы мог, конечно, посоветовать посмотреть на генерируемый этой штукой SQL запрос, да боюсь что понимания это не добавит По связям - надо смотреть модель, там будет указано как связаны друг с другом объекты, в т.ч. видно какие поля внешнего ключа и поля первичного ключа отвечают за такую связь со стороны БД. В принципе обычно из модели и так видно это. В VS подсказки помогут понять что же за q или там p подразумевается в каждом конкретном случае в лямбде. Хотя понимая параметры каждого метода это и так можно понять. Скажем для твоего примера, по шагам:
Ну вот как-то так и можно "разбирать" linq конструкции ------------------ WBR, Igor |
Re: c# winforms унифицировать обращение к TableAdapter | |
---|---|
Igor Korolyov Сообщений: 34580 Дата регистрации: 28.05.2002 |
Вопрос непонятен... CodeFirst подход предполагает в идеале: - нет базы, она будет создана из описания модели (т.е. из описанных бизнес-классов и "контекста"). - база создаётся и изменяется только посредством "миграций" - т.е. опять таки создаваемых на основании модели (классов предметной области типа Person и их контекста) специальных классов, где по сути прописывается какие таблицы создать/удалить/поля_добавить и т.п. В этот код (он генерируется) можно вносить изменения для "уточнения" процесса миграции - скажем то что надо не просто "удалить поле BirthDate и добавить поле Age а перенести инфу при помощи некоторого вычисляемого выражения, ну типа DateTime.Now.Year-BirthDate.Year - самое важное - код классов предметной области пишется вручную - он НЕ генерируется из БД. И если с первыми двумя пунктами ещё "есть варианты" (БД можно и вручную создать, если понимать как именно должны называться таблицы и поля, либо в OnModelCreating контекста прописать все "соответствия" между свойствами/классами и таблицами/полями), то желание генерить классы из описаний таблиц - явное противоречие самому подходу "Код СНАЧАЛА" Вообще не очень понимаю какие там визарды имеются в виду - вроде как на edmx и все эти громоздкие "метаописания" уже давно забили, а для "чисто кода" и Fluent-стиля описания маппинга, или даже атрибутов на свойствах/классах никаких визардов и нет И это ни разу не CodeFirst Сама инфраструктура для "рефреша" описана по ссылке. stackoverflow.com Но лично я не вижу смысла в подобной функциональности. Ни на фоксе я не делал "авторефрешащиеся по таймеру записи", ни на шарпе. Надо юзеру - нажми явно кнопку обновления (тогда когда надо, а не посредине процесса вбивания текста в поле - половину текста вбил, а оно рраз - и зарефрешило эту запись ). И получи не только "новое состояние для 1 записи", а полностью новый список - с добавленными другими юзерами записями, и без удалённых, или без изменённых так что они более не попадают под критерий отбора. Кстати, сам BindingSource вполне себе можно использовать как "посредник" между контекстом и DataSource всяких гридов. Теоретически, используя специфические внеSQL-ные функции некоторых серверов БД можно сделать "подписку на событие изменения в БД" - от СУБД зависит гранулярность (ну можно ли подписаться на изменение конкретной одной записи, или набора записей) и собственно возможности. Ну и от провайдеров. Насколько я в курсе "автоматом" это подключить нельзя никуда - ни к датасетам, ни к EF. Да и вообще для такого рода задач гораздо лучше подойдёт написание некоего "сервиса извещений" силами СУБД, или очень близкого к СУБД ПО, нежели просто "уведомления об изменении" от СУБД, и там паче поллинг (тупое перевыполнение запроса по таймеру). P.S. Ещё вариант - если БД закрыта, т.е. только твоя программа может её менять, то организуй промежуточный слой - сервис через который и будет происходить "общение" клиентов с БД - силами сервиса вполне можно рассылать оповещения о новых/изменённых записях. Лучше при этом не изобретать велосипед а использовать одно из решений на основе MessageQueue, скажем RabbitMQ - там вроде и дока вменяемая и для шарпа "клиентские библиотеки" есть. Всё прочее - все эти таймеры, шмаймеры - от лукавого P.P.S. Ну и как бы в общем совет - не научившись строить простейшие "велосипеды", не стоит спешить в автомобиле, и тем паче в авиа-строение Двунаправленная связь с БД - это достаточно специфическая и above intermediate фишка. Ни разу не для изучающего основы... ------------------ WBR, Igor Исправлено 2 раз(а). Последнее : Igor Korolyov, 09.08.18 16:24 |
Re: c# winforms унифицировать обращение к TableAdapter | |
---|---|
AlexSSS Автор Сообщений: 6113 Откуда: Tallinn, Estonia Дата регистрации: 19.09.2005 |
-
Исправлено 2 раз(а). Последнее : AlexSSS, 09.08.18 18:45 |
Re: c# winforms унифицировать обращение к TableAdapter | |
---|---|
AlexSSS Автор Сообщений: 6113 Откуда: Tallinn, Estonia Дата регистрации: 19.09.2005 |
будем считать, я придумал неудачный пример. Другой простейший пример, когда мне нужно обновить в локальном источнике только одну конкретную запись Есть таблица на сервере Есть такая же локальная таблица (не важно, как она реализована, таблица, список или еще что-то) Локальная таблица является источником для грида и нескольких контролов, в которых редактируются поля. Ищу нужную запись в гриде, при нажатии на кнопку Edit мне необходимо обновить в локальной таблице с сервера ОДНУ КОНКРЕТНУЮ ЗАПИСЬ, которую я буду редактировать. Чтобы на момент начала редактирования я видел актуальную информацию. Мне не надо тащить всю таблицу с сервера, мне нужно обновить лишь одну конкретную запись. На форме так же есть кнопка Refresh, по которой мне с сервера в локальную таблицу надо обновить только измененные и новые записи (timestamp > max(localTimestamp)). И опять же, мне не надо тащить с сервера всю таблицу Это что, авиастроение? ps. на датасетах это элементарно решается штатным способом Исправлено 3 раз(а). Последнее : AlexSSS, 09.08.18 18:48 |
Re: c# winforms унифицировать обращение к TableAdapter | |
---|---|
Аспид Сообщений: 3475 Откуда: Москва Дата регистрации: 01.04.2005 |
Нормальный подход источником для контролов этой формы формы будет Adres adres=db.Adreses.where(a=>a.id==id) Получишь актуальную на момент транзакции данные. А изначально ты притащил всю таблицу? Просто обновить полностью, с теми же условиями (т.е. полностью заново заполнить таблицу) Мне кажется это проще, чем манипуляции, в приведенной Игорем ссылке. Но по идее, что можно. получить еще один объект того же типа adr. И сравнивая, заполнить в начальном измененные. Наверное что то недопонимаю, но я не представляю себе алгоритма иного, либо отправлять на сервер- id,timestamp, и в случае изменения, получать, и заполнять. Просто не вижу быстрого выхода. А перезаполнить полностью актуальными данными... мне кажется самое быстрое. Я как и Игорь, не встречался с такой необходимостью. Даже при очень медленной связи, все равно, большой трафик, позаписное сравнение. Механизм то от языка не зависит. У тебя данные на клиенте. А изменения на сервере. Что бы узнать что поменялось, либо все отправить на сервер, и он решит что изменилось, либо получить все на клиента, сравнить, перезаписать... а там, не быстрее ли просто все вывести на экран. Или все же не понял задачи. Помнится 1 запись, конкретную хотел поменять, так это не сложно, кажется уже писал) Igor Korolyov Ну как всегда, во всем прав)) Отточенная терминология) Со всем согласен. Просто, я писал на эмоциях) А ты сухо разложил по полкам. ;) В конце концов, все на верном пути) ------------------ |
Re: c# winforms унифицировать обращение к TableAdapter | |
---|---|
AlexSSS Автор Сообщений: 6113 Откуда: Tallinn, Estonia Дата регистрации: 19.09.2005 |
чуть изменю вводные - редактирование идет в datagridview, но он настроен так, чтобы редактирование происходило только на одной записи. И перед редактированием в гриде мне надо обновить только одну конкретную запись. |
Re: c# winforms унифицировать обращение к TableAdapter | |
---|---|
AlexSSS Автор Сообщений: 6113 Откуда: Tallinn, Estonia Дата регистрации: 19.09.2005 |
нее, тут все гораздо проще вначале я получаю max(timestamp)в локальной таблице. на сервер идет ОДИН запрос, которые возвращает ВСЕ измененные позже записи select * from myTable where timestamp>?LocalMaxTimestamp что надо иметь в виду - при таком способе в локальной таблице останутся висеть записи, которые на сервере уже удалены. Исправлено 1 раз(а). Последнее : AlexSSS, 09.08.18 20:20 |
Re: c# winforms унифицировать обращение к TableAdapter | |
---|---|
Igor Korolyov Сообщений: 34580 Дата регистрации: 28.05.2002 |
Это задача нигде не решается "элементарно", поскольку по сути является задачей репликации данных между 2-мя хранилищами.
Проще всего её решать вынимая с сервера полностью "правильный свежий список" по тем же условиям что и шёл изначальный запрос, а потом сопоставлять две "таблицы". Твои таймстампы в общем случае не помогут, т.к. тогда надо: - запретить удаление (удалённые на сервере записи ты не увидишь т.е. твоя локальная копия будет считать что они всё ещё на месте) - как-то понять что "обновлённая запись" более не подходит под начальные критерии отбора, и её таки надо убрать из локального кэша (т.е. по сути надо дублировать "логику отбора" - ещё и в коде сопоставления "свежего" и старого состояний). При этом позаписное извлечение (если ты собирался вдруг рефрешить записи по одной, проверяя в запросе id+timestamp) вообще безумно медленно работает по сравнению с извлечением и обработкой даже 10000 записей но за 1 раз. Только я ещё раз повторюсь - так не делают. Это бессмысленно. Держать зачем-то локальный кэш, чтобы героически бороться с его устареванием... Тупо извлёк данные и работай с ними. Надо свежие - снова извлёк, старые выкинул (ну "изменения" вовремя послав на сервер - при вводе, или при нажатии кнопки типа Save). Не надо тебе "обновлять локальный кэш" всякими хитрыми способами. Лишнее это. P.S. Пока писал ты уже всё и затёр ------------------ WBR, Igor |
Re: c# winforms унифицировать обращение к TableAdapter | |
---|---|
AlexSSS Автор Сообщений: 6113 Откуда: Tallinn, Estonia Дата регистрации: 19.09.2005 |
>P.S. Пока писал ты уже всё и затёр
какой-то ответ я заменил уже несколько часов назад, поменяв на более удачную формулировку ;) Это задача нигде не решается "элементарно", поскольку по сути является задачей репликации данных между 2-мя хранилищами. код из самого первого сообщения легко и просто это решает код для обновления одной записи.
зачем позаписное?это все решается одним запросом Исправлено 4 раз(а). Последнее : AlexSSS, 09.08.18 22:12 |
Re: c# winforms унифицировать обращение к TableAdapter | |
---|---|
Igor Korolyov Сообщений: 34580 Дата регистрации: 28.05.2002 |
Зачем? Пользователь открывает список в 8 утра, а "редактировать запись" будет ближе к вечеру? Впрочем, если очень надо то это не проблема - код приведен (только не забыть указать ВСЕ объекты требующие рефреша, в т.ч. и подчинённые и коллекции). Зачем? Если "в процессе редактирования" она с тем же успехом будет изменена "кем-то третьим" на сервере, и к моменту сохранения всё равно будет "отличаться от состояния в локальной таблице"? Конфликты совместного изменения стоит решать именно в момент сохранения, а никак не пытаться их избежать невнятными рефрешами "при начале редактирования строки" - ибо это всё равно не поможет. Зачем? Чтобы получить несовпадающие данные в локальном кэше и на сервере? И в части удалённых записей и в части изменённых, где изменения затронули поля по которым осуществлялся начальный отбор... И в итоге уже через долю секунды после этого рефреша не иметь абсолютно никаких гарантий, что на сервере всё осталось в таком вот виде Это борьба с ветряными мельницами - вместо того чтобы использовать их для получения муки "Это" - это что? датасеты точно так же не дают никаких специальных функций для репликации - они точно так же содержат локальную и заведомо "устаревшую" копию данных. А рефреш делается не сложнее (для датасетов тоже придётся по связанным таблицам ходить и "данные по ссылкам" рефрешить - при том и не новых записей не получить, ни условия начальных ограничений не соблюсти)... Впрочем, каждый сам себе злобный буратина - придумал ненужную на практике и не реализуемую практически никогда схему работы с данными - ну теперь мучайся с её реализацией ------------------ WBR, Igor |
Re: c# winforms унифицировать обращение к TableAdapter | |
---|---|
Аспид Сообщений: 3475 Откуда: Москва Дата регистрации: 01.04.2005 |
ta.Fill(dsPort.vi_Ship); -- полное обновление
ta.FillByID(dsPort.vi_Ship, ID ?? 0); -- обновление 1й записи. Не совсем то что просил. По сути... редактирование в гриде... как то не камильфо... Ну отредактировал. Сохранил запись, и обновил ее. Именно, и только ее. Не вижу смысла, тем не менее, по моему, не сложно решается. Хоть на фоксе, хоть на шарпе. Но это вовсе не обновление по timestamp. Правильно подмечено, А этого мало что бы отказаться? Ну получил измененные... Нарисуй функцию, которая в объекте list<t> подменяет по id записи (объекты). Думаю все равно медленнее будет чем получение всего списка. Или у тебя очень долгое получение списка, и редки изменения, только этим можно объяснить такое желание? ------------------ Исправлено 1 раз(а). Последнее : Аспид, 09.08.18 22:14 |
Re: c# winforms унифицировать обращение к TableAdapter | |
---|---|
AlexSSS Автор Сообщений: 6113 Откуда: Tallinn, Estonia Дата регистрации: 19.09.2005 |
именно это я и просил. И именно это меня полностью устраивало обрати внимание на ta.ClearBeforeFill = false; в случае с одной записью Проблема с удаленными записями элементарно решается добавлением битового поля isDeleted физическим удалением этих записей скриптом по ночам. ;) Исправлено 2 раз(а). Последнее : AlexSSS, 09.08.18 22:51 |
Re: c# winforms унифицировать обращение к TableAdapter | |
---|---|
AlexSSS Автор Сообщений: 6113 Откуда: Tallinn, Estonia Дата регистрации: 19.09.2005 |
редактировать по одной записи в гриде - да, это бред. Это я просто привел, как пример. На деле у меня простые формы работают с одним источником (+ другие для связанных таблиц). Пример интерфейса приаттачен для этой формы есть один основной BindingSource. Он привязан как к гриду, так и контролам. Переделывать 15 уже готовых форм проекта на то, чтобы для грида использовать один источник, а для расшифрованных данных лругой - нет никакого желания. пример простой формы photos.app.goo.gl что касается вообще редактирования в гриде - для некоторых задач это обалденно удобный для пользователей способ пример photos.app.goo.gl Исправлено 5 раз(а). Последнее : AlexSSS, 09.08.18 23:02 |
Re: c# winforms унифицировать обращение к TableAdapter | |
---|---|
AlexSSS Автор Сообщений: 6113 Откуда: Tallinn, Estonia Дата регистрации: 19.09.2005 |
обновление одной записи в локальном кэше стандартными средствами решается просто
|
Re: c# winforms унифицировать обращение к TableAdapter | |
---|---|
AlexSSS Автор Сообщений: 6113 Откуда: Tallinn, Estonia Дата регистрации: 19.09.2005 |
хорошая заметка по обновлению локального кэша
codethug.com |
Re: c# winforms унифицировать обращение к TableAdapter | |
---|---|
Igor Korolyov Сообщений: 34580 Дата регистрации: 28.05.2002 |
BindingSource это просто посредник между "настоящим" источником данных (хоть датасет, хоть List<Person> - не имеет значения) и контролами на форме. К работе с данными это не имеет отношения. Собственно говоря, никто и не говорил тебе о том что обязательно надо разные источники использовать. Для одной формы это было бы вообще нелогично - в списке видеть "Вася", а в текстбоксе редактирования "Петя".
Рефреш объекта в контексте обновит именно сам объект - для одной записи в рамках контекста существует всего 1 экземпляр объекта - "материализованной записи". Т.е. он автоматом изменится и в List<T> и в одиночном T. И в каком-нить ещё третьем List<T> где данный объект фигурировал. Другое дело, насколько корректно (со всех точек зрения, но прежде всего для пользователя), к примеру, получив сначала некоторый список через запрос, скажем .Where (x => x.Company=="MS") после такого рефреша получить в списке объект с Company=="Apple" Я бы сказал что это лажа. И по сравнению с ней попытка поредактировать "старо выглядящий" объект "Вася из MS" и лишь при сохранении получить ошибку, что дескать он уже не Вася и уже не в MS работает - ну как-то логичнее и понятнее выглядит. Равно и перезапрос - в терминах датасетов "полный и с ClearBeforeFill = true" выглядит проще, логичнее и даже быстрее, чем мытарства с частичным рефрешем по таймстампу дающие лажу для удалённых записей и для изменённых в части критерия отбора... Я всё же надеюсь что критерий отбора существует, и ВСЯ таблица целиком не извлекается в интерфейс с сервера... ------------------ WBR, Igor |
Re: c# winforms унифицировать обращение к TableAdapter | |
---|---|
AlexSSS Автор Сообщений: 6113 Откуда: Tallinn, Estonia Дата регистрации: 19.09.2005 |
не извлекается. ;) кстати, одна из вещей EF на эту тему, которая меня сильно порадовала db.Manager.Find(8) - ищет запись по первичному ключу, если ее нет, то скачивает с сервера. |
Re: c# winforms унифицировать обращение к TableAdapter | |
---|---|
Igor Korolyov Сообщений: 34580 Дата регистрации: 28.05.2002 |
Да, в том и проблема винформс приложений, что там весьма сложно (хотя и возможно) НЕ держать открытым контекст неопределённо долгое время (собственно говоря это и приводит к проблемам "старья в кэше" - которые приводят к "странностям в очередных запросах"). Для веб проблема не стоит - там открыл контекст, вынул данные, и ЗАКРЫЛ контекст (он не живёт более чем время обработки отдельного HTTP запроса - и как правило это ОЧЕНЬ короткий интервал времени) - а сами данные, обычно ещё и трансформированные отправил в браузер клиенту - то что он там направил, или заново запросил будет работать через НОВЫЙ контекст, где данные будут актуальными. А то что висит на странице - будет висеть бесконечно - до тех пор пока пользователь не начнёт чего-нить тыкать - хоть рефреш, хоть то же редактирование вызывать (если оно отдельно от "списка" таки реализовано). Там скорее обратная задача стоит, как не долбить базу по 100 раз одними и теми же запросами (для разных клиентов или разных "страниц" по которым ходит один клиент), и хотя-бы пару минут держать всё это в кэше P.S. твоё стёртое сообщение ярчайший пример бесполезности "рефреша" данных перед началом редактирования Ну видел я твой текст (актуальное состояние БД на момент начала редактирования), а пока чего-то там думал и писал - оно (состояние в БД) УЖЕ изменилось. Ну и что делать в такой ситуации? И это я ещё не тот же самый элемент данных менял А так - ну вылезла бы ошибка что "некуда уже, мил человек, твои изменения сохранять - запись то, тю-тю". И ничем рефреш не помог... ------------------ WBR, Igor |
Re: c# winforms унифицировать обращение к TableAdapter | |
---|---|
AlexSSS Автор Сообщений: 6113 Откуда: Tallinn, Estonia Дата регистрации: 19.09.2005 |
от этого я и не отказывался ;) оно есть в сообщениях выше Цитата: надо было в самом первом сообщении указать, что я сейчас пишу на WinForms ;) по факту форма может болтаться открытой с утра до вечера. какие-то записи могут изменяться несколько раз в день. редактирование записи редко занимает больше пары минут. так что вероятность нарваться на то, что кто-то в это время изменил эту же запись крайне мала. а вот за время, пока была открыта форма - весьма вероятна |
© 2000-2024 Fox Club  |