問題を解決する方法はたくさんあります。それは、ソフトウェアシステムで役割とユーザーステータスを管理する場合です。この記事では、そのアイデアの簡単な進化と、いくつかの役立つヒントとコードサンプルを紹介します。
基本的な考え方
ほとんどのシステムでは、通常、役割が必要です。 およびユーザーのステータス 。
役割は権利に関連しています ユーザーが正常にログインした後にシステムを使用しているときに持つ役割。役割の例としては、「コールセンターの従業員」、「コールセンターのマネージャー」、「バックオフィスの従業員」、「バックオフィスのマネージャー」、「マネージャー」などがあります。一般的に、これは、ユーザーが適切な役割を持っている場合、ユーザーがいくつかの機能にアクセスできることを意味します。ユーザーが同時に複数の役割を持つことができると想定するのが賢明です。
ステータスははるかに厳密であり、ユーザーがシステムにログインする権限を持っているかどうかを決定します。ユーザーは1つのステータスのみを持つことができます 一度に。ステータスの例としては、「勤務中」、「休暇中」、「病欠中」、「契約終了」などがあります。
ユーザーのステータスを変更しても、そのユーザーに関連するすべての役割を変更しないでおくことができます。ほとんどの場合、ユーザーのステータスのみを変更する必要があるため、これは非常に役立ちます。コールセンターの従業員として働いているユーザーが休暇中の場合は、ステータスを「休暇中」に変更し、戻ったときに「勤務中」のステータスに戻すことができます。
ログイン中に役割とステータスをテストすることで、何が起こるかを判断できます。たとえば、ユーザー名とパスワードが正しい場合でも、ログインを禁止したい場合があります。現在のユーザーステータスが彼が働いていることを意味しない場合、またはユーザーがシステムで役割を持っていない場合は、そうすることができます。
以下に示すすべてのモデルで、テーブルstatus
およびrole
同じです。
テーブルstatus
id
フィールドがあります およびstatus_name
および属性is_active
。属性is_active
の場合 は「True」に設定されています。これは、そのステータスを持つユーザーが現在作業中であることを意味します。たとえば、ステータス「working」の属性はis_active
になります。 値がTrueの場合、その他(「休暇中」、「病欠中」、「契約終了」)の値はFalseになります。
ロールテーブルには、id
の2つのフィールドしかありません。 およびrole_name
。
user_account
テーブルはuser_account
この記事で提示された表。最初のモデルでのみ、user_account
テーブルには2つの追加属性(role_id
およびstatus_id
。
いくつかのモデルが提示されます。それらはすべて機能し、使用できますが、長所と短所があります。
シンプルモデル
最初のアイデアは、user_account
テーブル、テーブルを参照status
およびrole
。両方のrole_id
およびstatus_id
必須です。
これは設計が非常に簡単で、クエリを使用してデータを処理することもできますが、いくつかの欠点があります。
-
履歴(または将来)のデータは保持しません。
ステータスまたはロールを変更するときは、
status_id
を更新するだけです。 およびrole_id
user_account
テーブル。今のところは問題なく動作するので、変更を加えるとシステムに反映されます。ステータスと役割が過去にどのように変化したかを知る必要がない場合は、これで問題ありません。また、将来を追加できないという問題もあります。 このモデルにテーブルを追加せずに、役割またはステータス。おそらくそのオプションが必要な状況の1つは、来週の月曜日から誰かが休暇をとることがわかっている場合です。もう1つの例は、新しい従業員がいる場合です。今すぐ彼のステータスと役割を入力し、将来的に有効になるようにしたいのかもしれません。予定されているイベントがある場合の問題もあります。 役割とステータスを使用します。通常、翌営業日のデータを準備するイベントは、ほとんどのユーザーがシステムを使用していないときに実行されます(夜間など)。したがって、誰かが明日仕事をしない場合は、当日の終わりまで待ってから、必要に応じてその人の役割とステータスを変更する必要があります。たとえば、現在働いていて「コールセンターの従業員」の役割を担っている従業員がいる場合、彼らは電話をかけなければならないクライアントのリストを取得します。誰かが誤ってそのステータスと役割を持っていた場合、その人もクライアントを獲得し、私たちはそれを修正するために時間を費やす必要があります。
-
ユーザーは一度に1つの役割しか持てません。
通常、ユーザーは複数の役割を持つことができる必要があります システム内。たぶん、データベースを設計しているときは、そのようなものは必要ありません。ワークフロー/プロセスの変更が発生する可能性があることに注意してください。たとえば、クライアントは2つの役割を1つにマージすることを決定する場合があります。考えられる解決策の1つは、新しい役割を作成し、以前の役割のすべての機能をそれに割り当てることです。もう1つの解決策(ユーザーが複数の役割を持つことができる場合)は、クライアントが両方の役割を必要とするユーザーに割り当てるだけです。もちろん、その2番目のソリューションはより実用的であり、クライアントが自分のニーズに合わせてシステムをより迅速に調整できるようにします(これはこのモデルではサポートされていません)。
一方、このモデルには、他のモデルよりも大きな利点が1つあります。シンプルなので、ステータスや役割を変更するためのクエリも簡単です。また、ユーザーがシステムにログインする権限を持っているかどうかを確認するクエリは、他の場合よりもはるかに簡単です。
select user_account.id, user_account.role_id from user_account left join status on user_account.status_id = status.id where status.is_user_working = True and user_account.user_name = @user_name and user_account.password_hash_algorithm = @password;
@user_nameと@passwordは入力フォームからの変数であり、クエリはユーザーのIDとユーザーが持っているrole_idを返します。 user_nameまたはpasswordが無効な場合、user_nameとpasswordのペアが存在しない場合、またはユーザーにアクティブでない割り当て済みステータスがある場合、クエリは結果を返しません。そうすれば、ログインを禁止できます。
このモデルは、次の場合に使用できます。
- ユーザーが複数の役割を持つ必要のあるプロセスの変更はないと確信しています
- 履歴内の役割/ステータスの変更を追跡する必要はありません
- 役割やステータスの管理はあまり期待していません。
追加された時間コンポーネント
ユーザーの役割とステータス履歴を追跡する必要がある場合は、user_account
およびrole
およびuser_account
およびstatus
。もちろん、role_id
を削除します およびstatus_id
user_account
テーブル。モデルの新しいテーブルはuser_has_role
およびuser_has_status
終了時刻を除く、それらのすべてのフィールドは必須です。
テーブルuser_has_role
ユーザーがシステムでこれまでに持っていたすべての役割に関するデータが含まれています。代替キーは(user_account_id
、role_id
、role_start_time
)同じ役割を同時にユーザーに複数回割り当てる意味がないためです。
テーブルuser_has_status
ユーザーがシステムでこれまでに持っていたすべてのステータスに関するデータが含まれています。ここでの代替キーは(user_account_id
、status_start_time
)ユーザーは、まったく同時に開始する2つのステータスを持つことはできないためです。
新しい役割/ステータスを挿入すると、開始時刻がわかっているため、開始時刻をnullにすることはできません。役割/ステータスがいつ終了するかわからない場合は、終了時刻をnullにすることができます(たとえば、役割は明日から将来何かが起こるまで有効です)。
完全な履歴があるだけでなく、将来的にステータスと役割を追加できるようになりました。ただし、挿入または更新を行うときに重複をチェックする必要があるため、これは複雑になります。
たとえば、ユーザーは一度に1つのステータスしか持てません。新しいステータスを挿入する前に、新しいステータスの開始時刻と終了時刻を、データベース内のそのユーザーの既存のすべてのステータスと比較する必要があります。次のようなクエリを使用できます:
select * from user_has_status where user_has_status.user_account_id = @user_account_id and ( # test if @start_time included in interval of some previous status (user_has_status.status_start_time <= @start_time and ifnull(user_has_status.status_end_time, "2200-01-01") >= @start_time) or # test if @end_time included in interval of some previous status (user_has_status.status_start_time <= @end_time and ifnull(user_has_status.status_end_time, "2200-01-01") >= ifnull(@end_time, "2199-12-31")) or # if @end_time is null we cannot have any statuses after @start_time (@end_time is null and user_has_status.status_start_time >= @start_time) or # new status "includes" old satus (@start_time <= user_has_status.status_start_time <= @end_time) (user_has_status.status_start_time >= @start_time and user_has_status.status_start_time <= ifnull(@end_time, "2199-12-31")) )
@start_time
および@end_time
挿入するステータスの開始時刻と終了時刻、および@user_account_id
を含む変数です。 挿入するユーザーIDです。 @end_time
nullにすることができ、クエリで処理する必要があります。この目的のために、null値はifnull()
でテストされます 働き。値がnullの場合、高い日付値が割り当てられます(クエリでエラーに気付いたときに、長い間消えてしまうほど高い値です:)。クエリは、既存のステータスの開始時間と終了時間と比較して、新しいステータスの開始時間と終了時間のすべての組み合わせをチェックします。クエリがレコードを返す場合は、既存のステータスと重複しているため、新しいステータスの挿入を禁止する必要があります。また、カスタムエラーを発生させると便利です。
現在の役割とステータス(ユーザー権限)のリストを確認したい場合は、開始時刻と終了時刻を使用してテストするだけです。
select user_account.id, user_has_role.id from user_account left join user_has_role on user_has_role.user_account_id = user_account.id left join user_has_status on user_account.id = user_has_status.user_account_id left join status on user_has_status.status_id = status.id where user_account.user_name = @user_name and user_account.password_hash_algorithm = @password and user_has_role.role_start_time <= @time and ifnull(user_has_role.role_end_time,"2200-01-01") >= @time and user_has_status.status_start_time <= @time and ifnull(user_has_status.status_end_time,"2200-01-01") >= @time and status.is_user_working = True
@user_name
および@password
@time
の間、入力フォームからの変数です Now()に設定できます。ユーザーがログインしようとすると、その時点での権利を確認したいと思います。結果は、user_nameとpasswordが一致し、ユーザーが現在アクティブなステータスになっている場合に、ユーザーがシステムで持つすべての役割のリストです。ユーザーのステータスがアクティブであるが役割が割り当てられていない場合、クエリは何も返しません。
このクエリはセクション3のクエリよりも単純であり、このモデルにより、ステータスとロールの履歴を取得できます。さらに、将来のステータスと役割を管理でき、すべてが正常に機能します。
最終モデル
これは、パフォーマンスを向上させたい場合に、以前のモデルをどのように変更できるかについての単なるアイデアです。ユーザーは一度に1つのアクティブなステータスしか持てないため、status_id
を追加できます。 user_account
テーブル(current_status_id
)。そうすれば、その属性の値をテストでき、user_has_status
テーブル。変更されたクエリは次のようになります:
select user_account.id, user_has_role.id from user_account left join user_has_role on user_has_role.user_account_id = user_account.id left join status on user_account.current_status_id = status.id where user_account.user_name = @user_name and user_account.password_hash_algorithm = @password and user_has_role.role_start_time <= @time and ifnull(user_has_role.role_end_time,"2200-01-01") >= @time and status.is_user_working = True
明らかに、これによりクエリが簡素化され、パフォーマンスが向上しますが、解決する必要のあるより大きな問題があります。 current_status_id
user_account
次の状況では、テーブルを確認し、必要に応じて変更する必要があります。
-
user_has_status
テーブル - スケジュールされたイベントの毎日、誰かのステータスが変更されたかどうか(現在アクティブなステータスが期限切れになっているか、将来のステータスがアクティブになったか)を確認し、それに応じて更新する必要があります
クエリが頻繁に使用する値を保存することをお勧めします。そうすれば、同じチェックを何度も繰り返してジョブを分割することを回避できます。ここでは、user_has_status
テーブルを作成し、current_status_id
に変更を加えます それらが発生した場合(挿入/更新/削除)またはシステムがあまり使用されていない場合(スケジュールされたイベントは通常、ほとんどのユーザーがシステムを使用していない場合に実行されます)。この場合、current_status_id
しかし、これを同様の状況で役立つアイデアと見なしてください。