this のように、列挙型をDBに格納する方法についてのアドバイスを求める多くの質問を見てきました。しかし、なぜあなたはそれをするのだろうかと思います。したがって、Person
フィールドを持つエンティティgender
と、Gender
enumがあるとします。次に、私の人物テーブルに性別の列があります。
正確さを強制する明白な理由の他に、アプリケーションにすでにあるものをマップするために、なぜ追加のテーブルgender
を作成するのかわかりません。そして、私はそのような複製が本当に好きではありません。
概念や期待にこだわらない別の例を見てみましょう。ここには列挙型があり、それがバグの優先順位のセットです。
したがって、'C'
、'H'
、'M'
、および'L'
をデータベースに格納することができます。または'HIGH'
など。これには、stringly-typedデータの問題があります。有効な値の既知のセットがあり、そのセットをデータベースに保存することができない場合、操作が困難になる可能性があります。
List<String> priorities = {'CRITICAL', 'HIGH', 'MEDIUM', 'LOW'};
か、コードにその効果がある何かがあります。これは、このデータの適切な形式へのさまざまなマッピングがあることを意味します(データベースにすべての大文字を挿入していますが、Critical
として表示しています)。コードのローカライズも困難になりました。アイデアのデータベース表現を、コードに格納されている文字列にバインドしました。
このリストにアクセスする必要がある場合はどこでも、コードを複製するか、定数の束を持つクラスが必要です。どちらも良いオプションではありません。 otherこのデータを使用する可能性のあるアプリケーションがあることを忘れないでください(他の言語で記述されている可能性があります-Java Webアプリケーションには Crystal Reports 使用されるレポートシステムと Perl バッチジョブがデータをフィードします。レポートエンジンは、有効なデータのリストを知る必要があります( 'LOW'
優先度に何もマークされておらず、それがレポートの有効な優先度であることを知る必要がある場合はどうなりますか?)、バッチジョブには有効な値に関する情報が含まれます。
仮に、あなたは「私たちは単一言語のショップです-すべてがJavaで書かれている」と言い、この情報を含む単一の.jarを持っています-しかし、今ではapplicationsは互いに密接に結合されており、その.jarはデータを含んでいます。変更があるたびに、レポート部分とバッチ更新部分をWebアプリケーションと一緒にリリースする必要があります-そして、hopeそのリリースが進むことすべてのパーツをスムーズに。
あなたの上司が今日来ました。新しい優先度があります-CEO
。次に、すべてのコードを変更して、再コンパイルして再デプロイする必要があります。
「テーブル内の列挙」アプローチでは、列挙リストを更新して、新しい優先度を設定します。リストを取得するすべてのコードは、データベースからリストを取得します。
優先度を使用すると、ワークフローはotherテーブルへのキーとなり、ワークフローに関する情報、または誰がこの優先度を設定できるかなどを含むことができます。
少し質問で述べたように、性別に戻ります。性別には、使用中の代名詞he/his/him
とshe/hers/her
...へのリンクがあり、それをコード自体にハードコーディングすることは避けたい。そして、そしてあなたの上司がやって来て、あなたはあなたが'OTHER'
性別を持っていることを追加する必要があります(簡単にするために)そしてあなたはする必要がありますこの性別をthey/their/them
に関連付けます。上司はFacebookの内容を確認します...そうですね。
列挙型テーブルではなく文字列型のデータビットに制限することで、データと他のビットの間のこの関係を維持するために、その文字列を他のテーブルの束に複製する必要があります。
これをどこに保存しても、同じ原則が存在します。
priorities.prop
を作成できます。プロパティファイルからこのリストを読み取ります。enums
のエントリを持つドキュメントストアデータベース( CouchDB など)を作成できます(次に JavaScriptで検証関数を記述 ):
{
"_id": "c18b0756c3c08d8fceb5bcddd60006f4",
"_rev": "1-c89f76e36b740e9b899a4bffab44e1c2",
"priorities": [ "critical", "high", "medium", "low" ],
"severities": [ "blocker", "bad", "annoying", "cosmetic" ]
}
少しスキーマを含むXMLファイルを作成できます。
<xs:element name="priority" type="priorityType"/>
<xs:simpleType name="priorityType">
<xs:restriction base="xs:string">
<xs:enumeration value="critical"/>
<xs:enumeration value="high"/>
<xs:enumeration value="medium"/>
<xs:enumeration value="low"/>
</xs:restriction>
</xs:simpleType>
基本的な考え方は同じです。データストア自体は、有効な値のリストを格納して適用する必要がある場所です。ここに配置することで、コードとデータについてより簡単に推論できます。あなたは自分が何であるかを知っているので、毎回持っているものを守備的にチェックすることを心配する必要はありません(それは大文字ですか、それとも小文字ですか?なぜこの列にchritical
型があるのですか?など)。データストアからの取得は、データストアが送信を期待しているものとまったく同じです。有効な値のリストについてデータストアにクエリを実行できます。
有効な値のセットはdataであり、コードではありません。あなたdoは [〜#〜] dry [〜#〜] コードを求めて努力する必要がありますが、重複の問題はdataをその場所をデータとして尊重し、データベースに保存するのではなく、コード内で複製していること。
これにより、データストアに対する複数のアプリケーションの記述が容易になり、データ自体に密接に結合されているすべてのものをデプロイする必要があるインスタンスを回避できます-しないコードをデータに結合しました。
CEO
優先度が追加されたときにアプリケーション全体を再テストする必要がないため、アプリケーションのテストが簡単になります。優先度の実際の値を気にするコードがないためです。
コードとデータを互いに独立して推論できるため、メンテナンスの際にバグを見つけて修正することが容易になります。
クエリを読み取るときに間違いを起こしやすいのは、次のうちどれですか。
select *
from Person
where Gender = 1
または
select *
from Person join Gender on Person.Gender = Gender.GenderId
where Gender.Label = "Female"
SQLで列挙型のテーブルを作成するのは、後者の方が読みやすく、SQLの書き込みと保守のエラーが少なくなるためです。
Person
で性別を直接文字列にすることもできますが、その場合は大文字小文字を区別して適用する必要があります。また、DBが最適化にどれほど優れているかによっては、文字列と整数の違いにより、テーブルのストレージヒットとクエリ時間が増加する場合があります。
人々がこれについてまだ言及しなかったなんて信じられません。
データベースにenumを保持し、enum値を含むテーブルに外部キーを追加することにより、ensureはコードがその列に誤った値を入力することはありません。これはデータの整合性を助け、列挙型のテーブルがIMOに必要な最も明白な理由です。
私はあなたに同意するキャンプにいます。コードにGender列挙型を、データベースにtblGenderを保持すると、メンテナンス時に問題が発生する可能性があります。これら2つのエンティティは同じ値を持つ必要があることを文書化する必要があります。したがって、一方に加えた変更は、もう一方にも加える必要があります。
次に、列挙型の値を次のようにストアドプロシージャに渡す必要があります。
create stored procedure InsertPerson @name varchar, @gender int
insert into tblPeople (name, gender)
values (@name, @gender)
しかし、これらの値をデータベーステーブルに保持している場合、これをどのように行うかを考えてください。
create stored procedure InsertPerson @name varchar, @genderName varchar
insert into tblPeople (name, gender)
select @name, fkGender
from tblGender
where genderName = @genderName --I hope these are the same
確かに、リレーショナルデータベースは結合を考慮して構築されていますが、どのクエリが読みやすいですか?
次に、別のクエリ例を示します。
create stored procedure SpGetGenderCounts
select count(*) as count, gender
from tblPeople
group by gender
これとこれを比較してください:
create stored procedure SpGetGenderCounts
select count(*) as count, genderName
from tblPeople
inner join tblGender on pkGender = fkGender
group by genderName --assuming no two genders have the same name
次に、さらに別のクエリの例を示します。
create stored procedure GetAllPeople
select name, gender
from tblPeople
この例では、結果の性別セルをintからenumに変換する必要があることに注意してください。ただし、これらの変換は簡単です。これとこれを比較してください:
create stored procedure GetAllPeople
select name, genderName
from tblPeople
inner join tblGender on pkGender = fkGender
Enum定義をデータベースから除外するという考えに沿った場合、これらのクエリはすべて小さくなり、保守しやすくなります。
データ分析に使用できるという理由で、性別テーブルを作成します。データベース内のすべての男性または女性を検索して、レポートを生成できます。データを表示する方法が多いほど、トレンド情報を見つけやすくなります。明らかに、これは非常に単純な列挙ですが、複雑な列挙(世界の国や州など)の場合は、特殊なレポートを生成しやすくなります。
コードでビジネスロジックを駆動するために使用されるコード列挙がある場合でも、上/下で詳しく説明する多くの理由により、DB内のデータを表すテーブルを作成する必要があります。 DB値がコード値と常に同期していることを確認するためのヒントをいくつか紹介します。
テーブルのIDフィールドをIdentity列にしないでください。 IDと説明をフィールドとして含めます。
値が半静的であるか、コード列挙に関連付けられていることを開発者が理解できるように、表で別のことを行います。他のすべてのルックアップテーブル(通常、ユーザーが値を追加できる場所)では、通常、LastChangedDateTimeとLastChangedByを持っていますが、列挙型関連テーブルにそれらがないことは、それらが開発者によってのみ変更可能であることを思い出すのに役立ちます。これを文書化します。
列挙型の各値が対応するテーブルにあり、それらの値のみが対応するテーブルにあることを確認する確認コードを作成します。ビルド後に実行する自動化されたアプリケーション「ヘルステスト」がある場合は、そこにあります。そうでない場合、アプリケーションがIDEで実行されているときはいつでも、コードがアプリケーションの起動時に自動的に実行されるようにします。
同じことを行いますが、DB内からSQLスクリプトを提供する本番環境を作成します。正しく作成されていれば、環境の移行にも役立ちます。
最初に、データベースが1つのアプリケーションでのみ使用されるのか、それとも複数のアプリケーションで使用される可能性があるのかを決定する必要があります。場合によっては、データベースはアプリケーションのファイル形式にすぎません(この点でSQLiteデータベースを使用できることがよくあります)。この場合、列挙型定義をテーブルとしてビット複製することは、多くの場合うまくいく可能性があり、より理にかなっています。
ただし、データベースにアクセスする複数のアプリケーションの可能性を検討するようになり次第、列挙型のテーブルは非常に理にかなっています(他の答えは、詳細に説明されています)。考慮すべき他の事柄は、あなたや他の開発者が生のデータベースデータを見たいと思うでしょう。その場合、これは別のアプリケーションの使用と見なすことができます(ラボゲージが生のSQLである場合のみ)。
コード内で定義された列挙型(よりクリーンなコードとコンパイル時間のチェック用)とデータベース内のテーブルがある場合、ユニットテストを追加して、2つが同期していることを確認することをお勧めします。
データにアクセスするユーザーにも依存します。 1つのアプリケーションしかない場合は問題ないかもしれません。データウェアハウスまたはレポートシステムを追加する場合。彼らは、そのコードの意味、人間が編集可能なコードのバージョンを知る必要があります。
通常、型テーブルはコードの列挙型として複製されません。キャッシュされたリストにタイプテーブルをロードできます。
Class GenderList
Public Shared Property UnfilteredList
Public Shared Property Male = GetItem("M")
Public Shared Property Female = GetItem("F")
End Class
多くの場合、タイプは来たり来たりします。新しいタイプが追加された日付が必要です。特定のタイプがいつ削除されたかを知る。必要なときにだけ表示します。クライアントが性別として「トランスジェンダー」を望んでいるが、他のクライアントは望んでいない場合はどうなりますか?この情報はすべてデータベースに保存するのが最適です。