5

ユーザーはグループに所属できます。また、アイテム/製品には、そのアイテムを表示できるグループが割り当てられます。割り当てられたグループのいずれかに属している場合、ユーザーはそのアイテムを見ることができます。

パブリック (グループに属さない匿名ユーザー) もグループレス ユーザー (どのグループにも属さないログイン ユーザー) にもアイテムを表示したくありません。しかし、どのグループにも属しているユーザーがアイテムを見ることができるように、アイテムに「すべて/任意のグループ」属性を割り当てることができるインターフェイスが必要です。

この割り当てをどこに/どのように保存すればよいですか?

ps この手法は他のエンティティにも拡張されると思います。たとえば、ファイルをカテゴリに割り当て、グループをカテゴリにリンクします。そのため、ファイルが「すべて/任意のカテゴリ」によって表示可能としてマークされている場合、ユーザーが (グループおよびグループ カテゴリを介して) 少なくとも 1 つのカテゴリにリンクされている場合、ファイルはそれらに表示されます。

決断:

選択は、エンティティ グループ テーブルの行として実装するか、エンティティ テーブルのフィールドとして実装するかであると思われました。選択された答えは前者を使用しました。

そして、テーブル内のグループ メンバーシップを管理するか、JOIN 条件を追加します。選ばれた回答は前者を使用しましたが、後者を使用します。クエリと使用法の間に間接性を置いているので、(いつ) パフォーマンスに問題がある場合は、使用法を変更せずに (提案されているように) 下にあるマネージド テーブルに変更できるはずです。

「管理者」、「ユーザー」などの他の特別なグループがあります。これらは、エンティティごとに特別な変数フィールドを処理するよりも、同じ概念 (グループのリストが基本) に簡単に適合できます。

皆さんありがとう。

4

4 に答える 4

2

/ columnitemsとしてテーブルに入れます。booleanbitIsVisibleToAllGroups

ユーザーのすべてのアイテムを取得するためのクエリは少し単純ではありませんが、別の方法として、「すべてのグループ」を展開して、個々のグループごとに権限行を追加することもできますが、これにより、数が大幅に増加する可能性があります。追加のグループが後で追加された場合でも、これを最新の状態に保つ必要があり、すべての (現在および将来の) グループに明示的に付与されたアクセス許可と、たまたますべてのグループに付与されたアクセス許可を何らかの方法で区別する必要があります。現在存在しています。

編集使用しているRDBMSについては言及していません。もう 1 つの方法は、グループの階層を作成することです。

GroupId     ParentGroupId Name
----------- ------------- ----------
0           NULL          Base Group
1           0             Group 1
2           0             Group 2

次に、「すべての」権限を割り当ててGroupId=0使用できます(以下のSQL Serverアプローチ)

WITH GroupsForUser
     AS (SELECT G.GroupId,
                G.ParentGroupId
         FROM   UserGroups UG
                JOIN Groups G
                  ON G.GroupId = UG.GroupId
         WHERE  UserId = @UserId
         UNION ALL
         SELECT G.GroupId,
                G.ParentGroupId
         FROM   Groups G
                JOIN GroupsForUser GU
                  ON G.GroupId = GU.ParentGroupId)
SELECT IG.ItemId
FROM   GroupsForUser GU
       JOIN ItemGroups IG
         ON IG.GroupId = GU.GroupId  
于 2011-10-10T09:17:41.917 に答える
1

Martin Smith と Mikael Eriksson の両方が述べたように、これをエンティティのプロパティにすることは、非常に整然とした簡単なアプローチです。純粋にデータ表現という点では、これはとてもいい感じです。

ただし、データに対して実行する可能性が高いクエリについても検討します。たとえば、あなたの説明に基づいて、1 人のユーザーから始まり、そのユーザーがメンバーであるグループを見つけ、次にそれらが関連付けられているエンティティを見つけるクエリを作成する可能性が最も高いようです。ひょっとしたら、こんなことも…

SELECT DISTINCT -- If both user and entity relate to multiple groups, de-dupe them
  entity.*
FROM
  user
INNER JOIN
  user_link_group
    ON user.id = user_link_group.user_id
INNER JOIN
  group_link_entity
    ON group_link_entity.group_id = user_link_group.group_id
INNER JOIN
  entity
    ON entity.id = group_link_entity.entity_id
WHERE
  user.id = @user_id

この形式とエンティティ テーブルのプロパティのアイデアを使用する場合は、それほど洗練されていないものが必要になります。次の UNION アプローチがおそらく最も効率的だと思います...

<ORIGINAL QUERY>

UNION       -- Not UNION ALL, as the next query may duplicate results from above

SELECT
  entity.*
FROM
  entity
WHERE
  EXISTS (SELECT * FROM user_link_group WHERE user_id = @user_id)
  AND isVisibleToAllGroups != 0

-- NOTE: This also implies the need for an additional index on [isVisibleToAllGroups]

「どのエンティティを表示できますか」クエリでコーナー ケースを作成するのではなく、リンク テーブルのメンテナンスでコーナー ケースを作成するオプションです...

  1. GLOBAL グループを作成する
  2. エンティティがすべてのグループに表示される場合は、それらを GLOBAL グループにマップします
  3. ユーザーがグループに追加されている場合は、それらが GLOBAL グループにもリンクされていることを確認してください
  4. ユーザーがすべてのグループから削除された場合は、それらが GLOBAL グループからも削除されていることを確認してください

このように、元の単純なクエリは変更なしで機能します。これは、UNION が不要であることを意味します。これには、並べ替えと重複排除のオーバーヘッドがあり、isVisibleToAllGroups の INDEX も必要ありません。代わりに、オーバーヘッドは、ユーザーがリンクされているグループを維持することに移されます。代わりに、1 回限りのオーバーヘッドが発生します。

これは、「どのエンティティを表示できるか」という質問がグループの変更よりも一般的であることを前提としています。また、SCHEMA ではなく DATA によって定義される動作が追加されるため、適切なドキュメントと理解が必要になります。このように、私はこれを強力なタイプの最適化と見なしていますが、データベース設計で説明する必要があるトレードとバランスのタイプの妥協とも見なしています。

于 2011-10-10T09:44:17.493 に答える
0

すべてのクエリで追加のロジックが必要なブール値の代わりに、アイテムに必要なグループの名前(または番号)を含む列「needs_group」を追加します。NULL フィールドが「誰も」または「全員」を意味するかどうかは、(許可/拒否) 設計上の決定にすぎません。1 つの「パブリック」グループを作成し、全員をそこに入れることも、設計上の決定です。YMMV

于 2011-10-10T10:19:52.390 に答える
0

この概念はあなたを動かすはずです:

ここに画像の説明を入力

次の場合、ユーザーは製品を見ることができます。

  • 対応する行が USER_GROUP_PRODUCT に存在する
  • またはPRODUCT.PUBLICがTRUEです(質問を正しく理解していれば、ユーザーは少なくとも1つのグループに属しています)。

このモデルについて考慮すべき重要な点が 2 つあります。

  1. 識別関係の自由な使用- 親の主キーは、子の主キー内に「移行」されます。これにより、最下部の USER_GROUP_PRODUCT で GROUP_ID の「マージ」が可能になります。これにより、DBMS は、ユーザーと製品の両方が同じグループに属して相互に表示される必要があるという制約を適用できます。非識別関係と代理キーを使用すると、DBMS がそれを直接強制することができなくなります (カスタム トリガーを作成する必要があります)。
  2. PRODUCT.PUBLIC の使用法 - クライアント コードでは、このフィールドを「マジック」として扱う必要があります。別の方法は、単純に USER_GROUP_PRODUCT にすべての可能な組み合わせを入力することですが、このアプローチは、新しいユーザーが追加された場合には脆弱です。USER_GROUP_PRODUCT も更新しない限り、製品は自動的に表示されません。 PRODUCT.PUBLIC などのフィールドがない限り、更新しますか? どうせ PRODUCT.PUBLIC を避けられないのなら、それを特別に扱い、データベースの記憶領域をいくらか節約してみませんか?
于 2011-10-11T02:12:57.853 に答える