1

私はこのデータベーススキーマを持っています:

User  <--  UserRole  -->  Role

Role テーブルにはいくつかの列がありますが、主キーにのみ関心があり、UserRole の外部キーからそれを取得できるため、Role テーブルに参加する必要はまったくありませんが、方法がわかりませんEFでそのテーブルに参加しないようにします。

私はこのコードを試しました:

context.Users.Where(u => u.UserId == x).Single().Roles.Select(r => r.RoleId);

これにより、2 つのクエリが生成されます。user テーブルに 1 つ、UserRole と Role の結合に 1 つ。もちろん、.Include("Roles") または SelectMany() を使用して 1 つのクエリに減らすこともできますが、そのクエリでは 3 つのテーブルが結合されます。余分な結合を取り除く方法はありますか? SQL を次のようにしたい:

SELECT u.*, ur.RoleId
FROM User u
LEFT OUTER JOIN UserRole ur on ur.UserId = u.UserId
WHERE ...

実際にはオートマッパーを使用していますが、この例は同じ問題を示していると思います。Roles は小さなテーブルなので、今回はパフ​​ォーマンスの低下に耐えることができますが、手書きの SQL ほど効率的ではないことに悩まされています。私の前に他の誰かがこれに遭遇し、解決策を見つけましたか?

4

2 に答える 2

1

var以下を使用できます (ここでは型を明示するために使用しません)。

IQueryable<IEnumerable<int>> query = context.Users
    .Where(u => u.UserId == x)
    .Select(u => u.Roles.Select(r => r.RoleId));

IEnumerable<int> result = query.Single();

これ

  • UserId == xを持つユーザーが存在しない場合は例外をスローします。(あなたがあなたの例で使用しているので、あなたはそれを望んでいると思いますSingle。)
  • RoleIduser の のコレクションを返しますxresult.Count() == 0ユーザーがどの役割にも属していない場合、コレクションは空 ( ) になります。
  • とテーブルのみを結合するquery( with )の次の SQL を作成します。x == 1UserUserRoles

    SELECT 
    [Project1].[UserId] AS [UserId], 
    [Project1].[C1] AS [C1], 
    [Project1].[RoleId] AS [RoleId]
    FROM ( SELECT 
            [Extent1].[UserId] AS [UserId], 
            [Extent2].[RoleId] AS [RoleId], 
           CASE WHEN ([Extent2].[UserId] IS NULL) 
               THEN CAST(NULL AS int) 
               ELSE 1
           END AS [C1]
           FROM  [dbo].[Users] AS [Extent1]
           LEFT OUTER JOIN [dbo].[UserRoles] AS [Extent2]
               ON [Extent1].[UserId] = [Extent2].[UserId]
           WHERE 1 = [Extent1].[UserId]
         )  AS [Project1]
    ORDER BY [Project1].[UserId] ASC, [Project1].[C1] ASC
    

ユーザーが存在しないか存在するがロールを持っていないかを区別したくない場合は、次のクエリを使用してはるかに単純な SQL を取得できます。

IQueryable<int> query = context.Users
    .Where(u => u.UserId == x)
    .SelectMany(u => u.Roles.Select(r => r.RoleId));

IEnumerable<int> result = query.ToList();

ユーザーにロールがない場合、またはユーザーが存在しない場合、これは空のコレクションを返します。しかし、SQL は非常に単純です。

SELECT 
[Extent1].[RoleId] AS [RoleId]
FROM [dbo].[UserRoles] AS [Extent1]
WHERE 1 = [Extent1].[UserId]

したがって、関連するテーブル間の結合はまったくなく、クエリはUserRolesリンク テーブルのみを使用します。

于 2011-12-30T17:27:57.703 に答える
0

役割をより効率的に使用します。

ユーザーテーブルにロールを追加するためのチェックアウトフラグ。

フラグの機能:

以下を使用して一種の Enum を作成します。

Administrator = 1
Moderator = 2
SuperUser = 4
User = 8
Visitor = 16

ユーザーテーブルに属性ロールを整数として追加します。

"User" = Administrator + Moderator --> Role =  3 ( 1 + 2 )
"User" = Moderator + SuperUser     --> Role =  6 ( 2 + 4 )
"User" = SuperUser + User          --> Role = 12 ( 4 + 8 )

ジャンクション テーブルがなくなり、問題が解決しました。

(ただし、アプリケーションにロジックを追加するには、追加のコーディングが必要になります)

于 2011-12-30T15:58:24.537 に答える