CREATE TABLE tbl(key INTEGER PRIMARY KEY, cap TEXT NOT NULL);
Если вставить новую запись с полем cap='AAA' (INSERT), удалить ее (DELETE)
и вставить новую (INSERT) с cap='BBB'.
То по крайней мере в sqlite запись с cap='AAA' и c cap='BBB'
будут иметь одинаковый "key" (имеется ввиду удаленная запись с cap='AAA'
имела скажем key=1, и новая запись тоже будет иметь key=1).
Я разрабатываю приложение, которое должно позволить
открывать одну и ту же запись в разных независимых окнах (вернее множество
записей пересечение которые может быть не нулевое, но для упрощение ограничимся
одной записью).
И вот допустим мы прочитали какую-то запись из таблицы,
превратили ее в объект,и открыли этот объект в нескольких окнах.
В одном окне мы нажали кнопку удалить, потом создали новую запись,
в это время у нас все еще открыто третье окно в котором данные уже
удаленной записи, допустим мы в нем что-то меняем и нажимаем сохранить,
и получится ерунда какая-то, если использовать "key" как уникальный
идентификатор объекта базы.
Что в таким случаях делают, вводят типа "кэш" между классами отвечающими
за работу с базой и программой, и все GUI работающее с базой подписываются
на события "кэша" и если в одном окне объект удаляется, то "кэш" извещает
окна что такого объекта нет?
Здравствуйте, dave_2, Вы писали:
_>Возьмем для примера простейшую таблицу:
_>
_>CREATE TABLE tbl(key INTEGER PRIMARY KEY, cap TEXT NOT NULL);
_>
_>Если вставить новую запись с полем cap='AAA' (INSERT), удалить ее (DELETE) _>и вставить новую (INSERT) с cap='BBB'. _>То по крайней мере в sqlite запись с cap='AAA' и c cap='BBB' _>будут иметь одинаковый "key" (имеется ввиду удаленная запись с cap='AAA' _>имела скажем key=1, и новая запись тоже будет иметь key=1).
_>Я разрабатываю приложение, которое должно позволить _>открывать одну и ту же запись в разных независимых окнах (вернее множество _>записей пересечение которые может быть не нулевое, но для упрощение ограничимся _>одной записью).
_>И вот допустим мы прочитали какую-то запись из таблицы, _>превратили ее в объект,и открыли этот объект в нескольких окнах. _>В одном окне мы нажали кнопку удалить, потом создали новую запись, _>в это время у нас все еще открыто третье окно в котором данные уже _>удаленной записи, допустим мы в нем что-то меняем и нажимаем сохранить, _>и получится ерунда какая-то, если использовать "key" как уникальный _>идентификатор объекта базы.
_>Что в таким случаях делают, вводят типа "кэш" между классами отвечающими _>за работу с базой и программой, и все GUI работающее с базой подписываются _>на события "кэша" и если в одном окне объект удаляется, то "кэш" извещает _>окна что такого объекта нет?
С точки зрения бд тут всё ок — все сущности имеют уникальный первичный ключ. Проблема возникает от того, что клиенты работают с разными версиями данных. Решения: использовать транзакции, выбрать натуральный уникальный или первичный ключ, перенастроить что то в sqllite, что бы первичный ключ повторно не использовался бы.
Здравствуйте, Qulac, Вы писали:
Q>Здравствуйте, dave_2, Вы писали:
_>>Что в таким случаях делают, вводят типа "кэш" между классами отвечающими _>>за работу с базой и программой, и все GUI работающее с базой подписываются _>>на события "кэша" и если в одном окне объект удаляется, то "кэш" извещает _>>окна что такого объекта нет?
Q>С точки зрения бд тут всё ок — все сущности имеют уникальный первичный ключ. Проблема возникает от того, что клиенты работают с разными версиями данных. Решения:
> использовать транзакции,
А как это поможет? В описанном мной сценарии будет вызваться "update" с валидным ключом,
другое дело что хотим обновить старую версию данных, а обновляем новую. То есть sql часть
отработает без вопросов и ошибок.
> выбрать натуральный уникальный или первичный ключ, перенастроить что то в sqllite, что бы первичный ключ повторно не использовался бы.
Можно выставить свойства первичного ключа AUTOINCREMENT, и тогда все будет хорошо,
но напрягает что когда дело дойдет до 2^64-1 больше запись объектов будет невозможна (ограничение sqlite).
По идее пользователь за 1000 лет до такого не дойдет, но напрягает.
Re[3]: отображение строчек таблицы базы в объекты?
Здравствуйте, dave_2, Вы писали:
_>Здравствуйте, Qulac, Вы писали:
Q>>Здравствуйте, dave_2, Вы писали:
_>>>Что в таким случаях делают, вводят типа "кэш" между классами отвечающими _>>>за работу с базой и программой, и все GUI работающее с базой подписываются _>>>на события "кэша" и если в одном окне объект удаляется, то "кэш" извещает _>>>окна что такого объекта нет?
Q>>С точки зрения бд тут всё ок — все сущности имеют уникальный первичный ключ. Проблема возникает от того, что клиенты работают с разными версиями данных. Решения:
>> использовать транзакции,
_>А как это поможет? В описанном мной сценарии будет вызваться "update" с валидным ключом, _>другое дело что хотим обновить старую версию данных, а обновляем новую. То есть sql часть _>отработает без вопросов и ошибок.
Имелось в виду не давать нескольким пользователям изменять одни и те же данные или использовать оптимистическую блокировку.
>> выбрать натуральный уникальный или первичный ключ, перенастроить что то в sqllite, что бы первичный ключ повторно не использовался бы.
_>Можно выставить свойства первичного ключа AUTOINCREMENT, и тогда все будет хорошо, _>но напрягает что когда дело дойдет до 2^64-1 больше запись объектов будет невозможна (ограничение sqlite). _>По идее пользователь за 1000 лет до такого не дойдет, но напрягает.
Здравствуйте, dave_2, Вы писали:
_>Что в таким случаях делают, вводят типа "кэш" между классами отвечающими _>за работу с базой и программой, и все GUI работающее с базой подписываются _>на события "кэша" и если в одном окне объект удаляется, то "кэш" извещает _>окна что такого объекта нет?
Примерно так, только называется это не "кэш", а блокировки. При начале редактирования в форме происходит попытка заблокировать объект в БД. Если он уже заблокирован, пользователь получает сообщение об ошибке.
Это т.н. пессимистические блокировки. бывают еще оптимистические, но для простоты пока не будем о них.
SQLite не поддерживает блокировки на уровне отдельных строк, только таблицы целиком. Придется либо реализовать их в приложении, либо сменить СУБД.
Re[2]: отображение строчек таблицы базы в объекты?
W>Примерно так, только называется это не "кэш", а блокировки. При начале редактирования в форме происходит попытка заблокировать объект в БД. Если он уже заблокирован, пользователь получает сообщение об ошибке.
W>Это т.н. пессимистические блокировки. бывают еще оптимистические, но для простоты пока не будем о них.
W>SQLite не поддерживает блокировки на уровне отдельных строк, только таблицы целиком. Придется либо реализовать их в приложении, либо сменить СУБД.
Допустим в sqlite были бы пессимистические блокировки на уровне рядов таблицы.
Понятно как это поможет в сценарии взяли объект, поменяли и возвращаем на то место откуда взяли.
Но как они помогут в согласованности данных в разных окнах?
Допустим есть окно со списком объектов, двойным кликом открывается окно просмотра
объекта, в котором есть кнопки "Удалить" и "Редактировать".
При нажатии "Редактировать" или "Удалить" логично взять блокировку,
но как другие "окна" которые работают с базой только на чтение получат
информацию о том что что-то поменялось и надо вытащить данные заново?
Понятно как это делать когда окна редактирования модальные, и после возвращения
управления можно перечитать базу, а если они как в моем случае немодальные?
Re[3]: отображение строчек таблицы базы в объекты?
Здравствуйте, dave_2, Вы писали:
_>Допустим в sqlite были бы пессимистические блокировки на уровне рядов таблицы. _>Понятно как это поможет в сценарии взяли объект, поменяли и возвращаем на то место откуда взяли. _>Но как они помогут в согласованности данных в разных окнах?
Тут они действительно мало помогут. Блокировки на уровне БД нужны тогда, когда с базой независимо работают несколько пользователей. Я, когда отвечал выше, имел в виду именно такой сценарий. А синхронизация данных внутри одного экземпляра приложения, до того, как эти данные записаны в базу, — это забота разработчика приложения, то есть твоя.
_>Допустим есть окно со списком объектов, двойным кликом открывается окно просмотра _>объекта, в котором есть кнопки "Удалить" и "Редактировать". _>При нажатии "Редактировать" или "Удалить" логично взять блокировку, _>но как другие "окна" которые работают с базой только на чтение получат _>информацию о том что что-то поменялось и надо вытащить данные заново?
Например, окна могут слать друг другу уведомления. Ну или главному окну, которое будет пересылать их всем остальным.
Кстати, блокировки бывают и на чтение тоже, так что можно использовать и их, если это не будет мешать другим пользователям.
Autoincrement + успокоительные, чтобы не париться зазря.
+ Оптимистическая блокировка, типа (упрощенно, чтобы был понятен смысл оптимистической блокировки):
public void UpdateRecord(Record r)
{
int rowsUpdated = _db.Execute($"UPDATE records SET cap = 'blabla' WHEER Key = {r.Key} AND TimeStamp = '{r.TimeStamp}'"); // Вместо TimeStamp можно использовать int versionif (rowsUpdated == 0) // запись не найдена
{
// тут решаем что делать, например выкидываем исключение или проверяем что запись с Key = 1 всё еще в базе, и тогда можно предложить пользователю перезаписать её.
}
}
Здравствуйте, dave_2, Вы писали:
_>Что в таким случаях делают, вводят типа "кэш" между классами отвечающими _>за работу с базой и программой, и все GUI работающее с базой подписываются _>на события "кэша" и если в одном окне объект удаляется, то "кэш" извещает _>окна что такого объекта нет?
примерно так, только называют это не "кэш", а "модель". Все запросы в базу идут через модель, поэтому модель знает когда что-то поменялось в базе, и уведомляет об этом всех заинтересованных. В общем, вы близки к тому чтобы изобрести MVC.