Почему миграции Rails определяют внешние ключи в приложении, но не в базе данных? - PullRequest
35 голосов
/ 30 мая 2009

Если я определю модель Customer и Order, в которой Customer "имеет много" Orders, а Order "принадлежит" Customer, то в Rails мы говорим о Order наличие внешнего ключа от Customer до customer_id, но мы не имеем в виду, что это применяется в базе данных.

Поскольку Rails не определяет это как ограничение на уровне базы данных, существует риск нарушения целостности ваших данных, возможно, вне приложения (или внутри, если вы получаете одновременные запросы?), Если вы не применяете ограничение в базе данных вручную.

Почему Rails не определяет внешний ключ на уровне базы данных или есть способ заставить Rails сделать это?

class Customer < ActiveRecord::Base
  has_many :orders
end

class Order < ActiveRecord::Base
    belongs_to :customer
end

ActiveRecord::Schema.define(:version => 1) do

  create_table "customers", :force => true do |t|
    t.string   "name"
  end

  create_table "orders", :force => true do |t|
    t.string   "item_name"
    t.integer  "customer_id"
  end

end

Ответы [ 5 ]

22 голосов
/ 30 мая 2009

Rails придерживается некоторых соглашений, что обеспечение целостности данных должно выполняться в приложении, а не в базе данных.

Например, Rails даже поддерживает некоторые конструкции баз данных, в которых не может использовать внешние ключи , такие как полиморфные ассоциации.

По сути, соглашения Rails рассматривали базу данных как статическое устройство хранения данных, а не как активную СУБД. Rails 2.0 - это наконец , поддерживающий некоторые более реалистичные возможности баз данных SQL. Неудивительно, что в результате разработка с использованием Rails станет более сложной, чем в версии 1.0.

13 голосов
/ 30 мая 2009

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

Существуют валидации и проверки на уровне приложений, чтобы обеспечить простые, быстрые, удобочитаемые проверки (например, сообщения об ошибках), которые работают в 99,99% случаев. Если вашему приложению требуется нечто большее, вы должны использовать ограничения уровня базы данных.

Я думаю, что эта «философия» возникла из-за оригинальной используемой среды тестирования: внешние ключи оказались просто гигантскими хлопотами при использовании осветителей. Это как когда «ошибка» становится «функцией», потому что никто не исправляет ее. (Если я неправильно запоминаю историю, кто-то поправляет меня.)

Как минимум, в сообществе Rails усиливается движение за обеспечение целостности базы данных. Ознакомьтесь с этой записью в блоге за прошлый месяц. Она даже ссылается на некоторые плагины, которые помогают обеспечить поддержку обработки ошибок (и еще одну запись в блоге, которая ссылается на другие плагины). Сделайте еще несколько поисков в Google; Я видел другие плагины, которые добавляли поддержку миграций для создания внешних ключей.

Теперь, то, что является частью основной философии Rails, таково: не беспокойтесь о вещах, если вам это действительно не нужно. Для многих веб-приложений вполне возможно, что небольшой (возможно, крошечный) процент записей содержит недопустимые данные. Страницы, которые могут быть затронуты, могут быть просмотрены очень редко, или ошибка уже может быть исправлена. Или, может быть, дешевле (например, в виде наличных денег) решать проблемы вручную в течение следующих 6 месяцев по мере роста приложения, чем тратить ресурсы на планирование на все непредвиденные обстоятельства сейчас. По сути, если ваши варианты использования не делают все это важным, и это может быть вызвано только состоянием гонки, которое может произойти за 1/10000000 запросов ... ну, оно того стоит?

Так что я предсказываю, что по умолчанию будут появляться инструменты для лучшей обработки всей ситуации, и в конечном итоге они будут объединены в Rails 3. А пока, если ваше приложение действительно нуждается в этом, добавьте их. Это вызовет небольшую головную боль при тестировании, но ничего такого, с чем вы не сможете справиться с помощью издевательств и заглушек. И если вашему приложению это не нужно ... ну, у вас все хорошо. :)

6 голосов
/ 23 марта 2011

После многих десятилетий в отрасли я твердо уверен, что хороший дизайн базы данных избавит приложение от многих проблем, особенно когда оно подвергается усовершенствованиям. Если известно, что конкретное ограничение сохранит целостность базы данных даже после промахов в программировании (я уверен, что я не единственный, кто это делает), то это, безусловно, следует применять к базе данных, если это возможно. Поэтому я бы посоветовал людям использовать внешние ключи, когда это возможно. Я также хотел бы рассмотреть возможность использования тестов для обеспечения целостности данных. Потому что мы все знаем о законе Мерфи.

4 голосов
/ 04 сентября 2009

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

Для миграций я бы использовал http://github.com/matthuhiggins/foreigner/tree/master. Вам не нужно менять свои модели, чтобы получить внешние ключи для работы с Rails.

2 голосов
/ 30 мая 2009

Создает столбец customer_id (очевидно). По большей части, однако, Rails верит в обеспечение ограничений и проверок на уровне приложения , а не на уровне базы данных; Вот почему столбцы по умолчанию в Rails могут содержать значения NULL, даже если у вас есть validates_presence_of или что-то в этом роде. По мнению разработчиков Rails, такие ограничения должны обрабатываться приложением, , а не базой данных.

...