Как обрабатывать ссылочную целостность для вставок в Access

Я работаю над проектом Access, который перенял у коллеги. Существуют три таблицы: rules, overview и relationship. Таблица relationship имеет два поля, каждое из которых является внешним ключом, связанным с первичным ключом в двух других таблицах. У меня есть представление таблицы rules в форме, где я могу без проблем удалять записи. Однако, когда я пытаюсь вставить запись в таблицу rules, запись будет вставлена ​​в таблицу rules, но в таблицу relationship нет соответствующей записи. У меня установлен флажок «Принудительно ссылочная целостность», а также «Каскадное обновление связанных полей» и «Каскадное удаление связанных записей». Я сделал наивное предположение, что это справится со вставками, но явно ошибался. Итак, теперь мне интересно, как лучше всего справиться с этим - написать какой-нибудь VBA для события After Insert формы, которая соответственно вставляет запись в таблицу relationship?


person Mitch    schedule 13.09.2011    source источник
comment
Если ваши PK являются полями автонумерации, нет смысла включать CASCADE UPDATE, поскольку поля автонумерации не могут быть обновлены.   -  person David-W-Fenton    schedule 15.09.2011


Ответы (2)


Обычный способ заключается в том, чтобы иметь форму для вставки записей в правила, основанную на запросе, который включает таблицу отношений и, скажем, комбинацию, которая позволяет пользователю выбрать соответствующий обзор, или настройку формы/подформы с подходящие главные/дочерние поля. В образце базы данных NorthWind таблица сведений о заказе является примером вашей таблицы отношений, в ней используется ненавистная анти-функция поиска в таблице, но вы можете получить некоторые идеи для дальнейших исследований.

Намного более подробное описание варианта 1

Таблицы

Обзор
ID
Обзор

Правила
Идентификатор
Правило

Relationship
RulesID ) PK, образованный двумя FK
OverviewID )

Отношения

Отношения

Данные

Данные

Предложение 1. Дизайн запроса

Обратите внимание, что оба поля из Отношения включены в запрос. Нет необходимости показывать ID из правил, потому что это поле автонумерации, но здесь оно включено для простоты.

При удалении строки записи из обеих таблиц будут удалены.

Дизайн запроса

Вы не можете нарушать ссылочную целостность. Вам нужно будет создать все обзоры, прежде чем это сработает, или предоставить другой метод добавления обзоров.

Нарушение целостности

Если вы обновите RulesID и OverviewID, запись будет добавлена ​​в таблицу Relationship, но не в Rules.

Новая запись о взаимоотношениях

Если вы обновите OverviewID и Rule, записи будут добавлены как в отношения, так и в правила.

Новые записи правил и отношений

Если вы создаете непрерывную форму, у вас есть все вышеперечисленное в гораздо более удобном для пользователя виде с большим контролем. Вы можете использовать поле со списком, чтобы позволить пользователю выбрать более понятное описание обзора, а не идентификатор, и вы можете воспользоваться событием NotInList для добавления новых обзоров.

непрерывная форма

Обратите внимание, что до сих пор для этого не потребовалось ни одной строки кода. В этом сила Access.

person Fionnuala    schedule 13.09.2011
comment
Спасибо за ответ, Рему. Я пытаюсь использовать представление таблицы данных, так как кажется, что все операции (вставка/обновление/удаление) могут выполняться через него. У меня есть настройка, которая звучит идентично тому, что вы упомянули в первом абзаце, где записи, отображаемые в представлении таблицы, основаны на выбранном типе обзора в поле со списком. Итак, вы думаете, что After Insert будет хорошим местом для вставки новой строки в таблицу relationship, когда вставки происходят в подчиненной форме/таблице данных? - person Mitch; 14.09.2011
comment
У меня это работает, используя After Insert. Я бы предоставил ссылку на pastebin для всех, у кого есть эта проблема, но она заблокирована на работе. - person Mitch; 14.09.2011
comment
@Mitch Нет необходимости писать какой-либо код, чтобы делать то, что вы хотите. см. выше. - person Fionnuala; 14.09.2011
comment
Спасибо за подробную правку. Несколько вопросов: 1) Вы сделали свои внешние ключи первичными ключами таблицы relationship - нужно ли это, если они уже настроены на проиндексированные (дубликаты в порядке)? 2) Запретить маркеры первичного ключа в таблице relationship, отношения моих таблиц идентичны тем, которые вы опубликовали. Вы сказали, что если я обновлю OverviewID и Rule, записи будут добавлены как в Relationship, так и в Rules, но на самом деле это не то, чего я хочу — пользователь не должен этого делать. Я хочу иметь возможность добавить запись в rules и распространить ее на relationship. - person Mitch; 15.09.2011
comment
3) Что касается непрерывной формы, я уверен, что она у меня уже есть. У меня есть представление таблицы rules, в котором отображаются только те правила, которые имеют соответствующий обзор в таблице отношений, который совпадает с тем, что пользователь выбрал в поле со списком обзора (которое не отображает идентификаторы). - person Mitch; 15.09.2011
comment
@Mitch Дубликаты двух внешних ключей не должны быть возможны в соединительной таблице, которой является таблица отношений. Как вы видите добавление OverViewID в таблицу отношений, если пользователь не выбирает идентификатор? - person Fionnuala; 15.09.2011
comment
Я думаю, что мы говорим о немного разных вещах. Я уточнял, что пользователь выбирает идентификатор обзора из поля со списком, но их список параметров представляет собой описание каждого обзора, а не идентификатор. Я хотел бы, чтобы они могли вставить новую строку в представление таблицы rules после того, как они выбрали обзор из поля со списком (который фильтрует отображаемые правила по обзору), который затем будет вставлен в rules и соответствующий запись вставлена ​​в relationship. - person Mitch; 15.09.2011
comment
Что касается ключей в таблице relationship, я приношу извинения за то, что не упомянул, что для rulesID установлено значение Indexed (No Duplicates), поскольку в обзоре может быть несколько правил. - person Mitch; 15.09.2011
comment
Я думаю, что лучше всего было бы отправить вам образец базы данных. Я совершенно уверен, что пример, который я привел, - это то, что вам нужно. Если ключом к отношениям является комбинация RulesID и OverviewID, то у вас может быть много одинаковых правил и много одинаковых обзоров, но не один и тот же обзор с одним и тем же правилом. - person Fionnuala; 15.09.2011
comment
Звучит отлично. Я бы предпочел не оставлять здесь свой адрес электронной почты. Могу ли я передать его вам каким-либо другим способом? Я не вошел в свою настоящую учетную запись, потому что я вхожу через свою учетную запись Google, которая заблокирована на работе. - person Mitch; 15.09.2011
comment
Используйте чат, см. строку: Please avoid extended discussions in comments. Would you like to automatically move this discussion to chat? - person Fionnuala; 15.09.2011
comment
Я пробовал это раньше, и возникла ошибка, затем я щелкнул ссылку чата вручную, и оказалось, что это тоже заблокировано ... все в этом месте заблокировано, ха-ха. - person Mitch; 16.09.2011
comment
@Mitch Rats :) Зайдите на lessthandot.com, это технический сайт, поэтому его нельзя заблокировать. У него есть личные сообщения для меня, или просто напишите сайту, и кто-нибудь скажет мне. - person Fionnuala; 16.09.2011
comment
Вау, моя работа настолько ужасна, что они блокируют страницу, на которую мне нужно перейти, чтобы активировать мою учетную запись с менее чем точкой. Почему я снова здесь? - person Mitch; 19.09.2011

Если рассматриваемый ключ является автономером (IDENTITY) и одна таблица ссылается на другую (через внешний ключ), то вы можете создать VIEW, объединяющий две таблицы, вставить в представление, и значение автонумерации будет автоматически скопировано в ссылочную таблицу. Вот краткая демонстрация:

Sub RulesOverview()
  On Error Resume Next
  Kill Environ$("temp") & "\DropMe.mdb"
  On Error GoTo 0

  Dim cat
  Set cat = CreateObject("ADOX.Catalog")

  With cat
    .Create _
    "Provider=Microsoft.Jet.OLEDB.4.0;" & _
    "Data Source=" & _
    Environ$("temp") & "\DropMe.mdb"

    With .ActiveConnection

      Dim Sql As String

      Sql = _
      "CREATE TABLE Rules ( " & _
      " ID INTEGER IDENTITY NOT NULL UNIQUE,  " & _
      " Rule VARCHAR(30) NOT NULL UNIQUE " & _
      ")"

      .Execute Sql

      Sql = _
      "CREATE TABLE Overview ( " & _
      " OverviewID INTEGER IDENTITY NOT NULL UNIQUE, " & _
      " Overview VARCHAR(30) NOT NULL UNIQUE " & _
      ")"

      .Execute Sql

      Sql = _
      "CREATE TABLE Relationship ( " & _
      " RuleID INTEGER NOT NULL " & _
      "    REFERENCES Rules (ID) " & _
      "    ON DELETE CASCADE, " & _
      " OverviewID INTEGER " & _
      "    REFERENCES Overview (OverviewID) " & _
      "    ON DELETE SET NULL, " & _
      " Name VARCHAR(20) NOT NULL, " & _
      " UNIQUE (RuleID, OverviewID) " & _
      ")"

      .Execute Sql

      Sql = _
      "CREATE VIEW RulesRelationship AS " & _
      "SELECT Rules.ID, " & _
      "       Rules.Rule, " & _
      "       Relationship.RuleID, " & _
      "       Relationship.Name " & _
      "  FROM Rules INNER JOIN Relationship " & _
      "          ON Rules.ID = Relationship.RuleID;"

      .Execute Sql

      Sql = _
      "INSERT INTO RulesRelationship (Rule, Name) " & _
      "   VALUES ('Don''t run with scissors', " & _
      "           'Initial scissors');"

      .Execute Sql

      Sql = _
      "SELECT * FROM RulesRelationship;"

      Dim rs
      Set rs = .Execute(Sql)
      MsgBox rs.GetString

    End With
    Set .ActiveConnection = Nothing
  End With
End Sub
person onedaywhen    schedule 14.09.2011
comment
Для меня не сразу очевидно, будет ли это работать со структурой таблицы, которую опубликовал Рему (поскольку это мое упрощенное изображение). - person Mitch; 15.09.2011
comment
@Mitch: В вашей спецификации сказано, что когда вы вставляете запись в таблицу rules, вы хотите, чтобы соответствующая строка автоматически вставлялась в отношение table. Этого можно добиться с помощью модели, которую я опубликовал (я, конечно, изменил имена таблиц). Однако, используя модель @Remou (цитата), вам нужно будет создать все обзоры, прежде чем это сработает, или предоставить другой метод добавления обзоров. Я решил ответить на ваш вопрос, а не опираться на ответ @Remou;) - person onedaywhen; 15.09.2011
comment
@Mitch: я обновил свой пример кода, чтобы использовать метаданные из ответа @Remou, добавил атрибут Relationship.Name для демонстрационных целей. - person onedaywhen; 15.09.2011