web-dev-qa-db-ja.com

データ検証をサポートするORMの場合、データベースにも制約を適用する必要がありますか?

私の(ActiveRecord)モデルに加えて、常にデータベースレベルで制約を適用しています。しかし、これが本当に必要かどうか疑問に思っていましたか?

少し背景

私は最近、モデルの基本的な自動タイムスタンプ生成方法を単体テストする必要がありました。通常、テストではモデルのインスタンスが作成され、検証なしで保存されます。ただし、テーブル定義のでnullにできない他の必須フィールドがあります。つまり、ActiveRecord検証をスキップしても、インスタンスを保存できません。だから私はそのような制約をデータベース自体から削除し、ORMにそれらを処理させるべきかどうか考えていますか?

可能性のある利点dbで制約をスキップした場合、imo-

  • データベースを移行することなく、モデルの検証ルールを変更できます。
  • テストの検証をスキップできます。

考えられる欠点?

ただし、ORM検証が失敗またはバイパスされる可能性がある場合でも、データベースは制約をチェックしません。

どう思いますか?

[〜#〜] edit [〜#〜]この場合、私は Yii Framework を使用しています。データベースからのモデル、したがってデータベースルールも生成されます(自分で生成したものを後から作成することもできます)。

13
n a

あなたの指針となる原則は Do n’t Repeat Yourself です。

ソフトウェアエンジニアリングでは、Do n't Repeat Yourself(DRY)は、あらゆる種類の情報の繰り返しを減らすことを目的としたソフトウェア開発の原則であり、特に多層アーキテクチャで役立ちます。 DRY=原則は、「すべての知識は、システム内に単一の明確で信頼できる表現を持たなければならない」と述べられています。

ORMは基本的に追加のレイヤー(または必要に応じて層)であり、アプリケーションとデータストレージの間に快適に配置されます。 ORMまたはのいずれであっても、制約は1か所のみである必要があります。それ以外の場合は、さまざまなバージョンの保守を行うことになります。あなた本当にしたくないです。

ただし、実際には、ほとんどのORMは、データスキーマから大量のモデルを自動的に生成します。重複はまだありますが、複製されたORMコードは毎回同じパターンに従って生成されるため、メンテナンスが地獄になる可能性は最小限です。重複するコードがないことが理想的ですが、自動的に生成される制約が次善の策です。

また、制約を1か所に置いても、必ずしも制約が同じ場所にallあるはずです。参照整合性制約など、一部はデータストレージに適している可能性があります(ただし、別のデータストレージに移動すると失われる可能性があります)。一部は、主に複雑なビジネスロジックに関するもので、ORMに適しています。すべてのリンゴを同じバスケットに入れるのが望ましいですが…

失敗

ORMの失敗について言及します。それはあなたの質問とはまったく無関係です。アプリケーションはORMとデータストレージを単一のエンティティとして考える必要があります。失敗した場合、失敗し、ORMをバイパスしてデータストレージと直接通信することは良い方法ではありません

その他のORMのバイパス

また、良い考えではありません。ただし、さまざまな理由で発生する可能性があります。

  1. ORMが導入される前に構築されたアプリケーションのレガシー部分。

    それは難しい問題であり、まさに私が今で扱っている状況であり、それゆえ、私の「地獄のメンテナンス」が繰り返し繰り返されています。 ORM以外のパーツを維持するか、ORMを使用するようにパーツを書き直します。 2番目のオプションmightは最初はより理にかなっていますが、これは、アプリケーションのこれらの部分が正確に何をしているかに基づいて決定することであり、完全な書き換えが長期的にどれだけ価値があるかです実行します。

    不適切に設計された2 * 10 ^ 8行のMySQLテーブルのキーを(ダウンタイムなしで)変更してみてください。そうすれば、私がどこから来たのか理解できます。

  2. データストレージと直接通信する必要があるアプリケーションの非レガシー部分:

    さらにトリッキーです。 ORMは優れたツールであり、ほとんどすべてを処理しますが、邪魔になることもあれば、まったく役に立たないこともあります。流行語(実際の語句)は オブジェクトリレーショナルインピーダンスの不一致 であり、ORMがリレーショナルデータベースで行うことすべてを行うことは技術的に不可能であり、彼らが行うことのいくつかについては、パフォーマンスが大幅に低下します。

コメント

データの整合性の観点から、制約はデータベースにある必要があり、アプリケーションにある必要があります。アプリケーションがWebおよびデスクトップアプリケーション、モバイルアプリ、またはWebサービスからアクセスされた場合はどうなりますか? – Luiz Damim

ここで、追加のレイヤーを追加すると非常に役立ちます。Webアプリケーションの場合は、REST API。 過度に単純化した設計 を使用します。これは:

enter image description here

ORMはAPIとデータストレージの間に位置し、APIの背後にあるすべてのもの(それを含む)は、さまざまなアプリケーションの単一のエンティティと見なされます。

16
yannis

これは実際には答えるのが非常に難しい質問であり、非常に物議を醸すテーマであることがわかりました。

Yannis Rizosが彼の回答で指摘したように、制約ロジックをデータベースとORMレイヤーの両方に含めると、DRYに違反するように見えるため、「メンテナンスの悪夢、不十分な因数分解、論理的な矛盾が発生する可能性があります」。

ただし、データベースから制約ロジックを削除して保持するORMレイヤーのみは、次のいずれかの条件がある場合は機能しません。

  1. 手動によるDBの更新(すべての会社で行われているようです)

  2. ORM制約ロジックを常に簡単に共有できない別のシステムからのDBの更新(ORMレイヤーがHibernateに実装され、Javaアプリケーションで使用されるときにルーチンタスクを実行するPerlスクリプトなど)日帰り活動)

これは、DRY違反を防ぐためにDBに制約ロジックを追加してORMレイヤーから削除するだけを推奨します。ただし、これにより、アプリケーションコードが実際の問題を正常にキャプチャしてユーザーに伝えることができない場合(開発者が問題をデバッグしている場合は可能です)これは、一部のプロジェクトでは受け入れられない場合があります。

最後のオプションは、ORM(および他のシステム)でDB制約から制約の自動作成にすることです(または、実際には...逆も同様です)。最終的には制約の2つ以上の実装になることになりますが、「実用的なプログラマ」で説明されているDRY原則)の違反にはなりません。 DRY違反を回避します。たとえば、DB制約を変更するたびに、それを使用するすべてのアプリケーションの再ビルドと再デプロイが強制される可能性があるため、これは単純ではありません。 (自動化するのは簡単ではありません)。

実際、それはケースバイケースで評価する必要がありますです。この時点で、制約ロジックを繰り返さないように提案すると、空白の視線に遭遇したことになります。

20
smp7d

私は間違いなく、デフォルトのオプションとしてデータベースに制約を追加します。これは、企業にとってデータが王であり、データ品質が最も重要だからです。 @Yannis RizosはDRY原理を議論に持ち込みました。もう1つの原理は多層防御です。データにはこの原理を使用します。

私は、DBに30年前に作成されたデータがある実際の企業で働いていました。 COBOLアプリケーションからアクセスされ、今でも.Netアプリケーションからアクセスされています。 10年後にはベンダーアプリになる可能性があります。合併があり、何百万ものデータ行が変換され、SQLを使用して他社からこのデータベースに移行されました。 ORMはこれを行うことができません。結論としては、データが残り、アプリケーションが変化し、データの生成方法が変化します。では、データ破損の可能性を減らしてみませんか?

3
softveda

どちらもある程度はできると思います。

  • 主な制約はORMに存在する必要があります。プログラミング言語ははるかに柔軟であり、テストが容易であり、要件が変更された場合の調整が容易です。少なくともDDLの修正について心配する必要はありません。また、データの回帰問題をテストするのは困難です。

  • 非常に厳格で高速な制約もデータベースに存在する必要があります。たとえば、nullにできない名前について話しているのではありません。参照整合性や絶対に重要な識別子が必要なことなどについて話している。コードが「注文に存在しない製品がある場合はどうなるか」を処理する必要がない構造上の要件。

2
Wyatt Barnett

データベースがIMOであるDRYが違反される可能性があるのは、ORMをバイパスして不正なデータがある場合、それだけです。ゲームオーバー。破損したデータを持つことは致命的な打撃です。

1
Wayne Molina