Я использую Entity Framework в Visual Studio 2010 Beta 2 (.NET Framework 4.0 Beta 2). Я создал модель базы данных .edmx из моей базы данных, и у меня есть несколько взаимосвязей «многие ко многим».
Тривиальным примером моей схемы базы данных является
- Роли (ID, Имя, Актив)
- Члены (ID, DateOfBirth, DateCreated)
- RoleMembership (RoleID, MemberID)
Сейчас я пишу пользовательский поставщик ролей (Inheriting System.Configuration.Provider.RoleProvider) и пришел написать реализацию IsUserInRole (username, roleName).
Запросы LINQ-to-Entity, которые я писал, когда SQL-Profiled, производили операторы CROSS JOIN, когда я хочу, чтобы они INNER JOIN.
Dim query = From m In dc.Members
From r In dc.Roles
Where m.ID = 100 And r.Name = "Member"
Select m
Моя проблема почти точно описана здесь:
Платформа сущностей и многие ко многим запросам непригодны?
Я уверен, что представленное там решение работает хорошо, но хотя я изучал Java в универе и в основном понимаю C #, я не могу понять предоставленный синтаксис Lambda, и мне нужно получить аналогичный пример в VB. Большую часть дня я просматривал в Интернете, но я не приблизился к своему ответу.
Поэтому, пожалуйста, кто-нибудь может посоветовать, как в VB я могу создать оператор LINQ, который бы делал этот эквивалент в SQL:
SELECT rm.RoleID
FROM RoleMembership rm
INNER JOIN Roles r ON r.ID = rm.RoleID
INNER JOIN Members m ON m.ID = rm.MemberID
WHERE r.Name = 'Member' AND m.ID = 101
Я бы использовал этот запрос, чтобы увидеть, есть ли Участник 101 в Роли 3.
(Я понимаю, что мне, вероятно, не нужно объединяться с таблицей Members в SQL, но я думаю, что в LINQ мне нужно будет ввести объект Member?)
UPDATE:
Я немного ближе, используя несколько методов:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim count As Integer
Using dc As New CBLModel.CBLEntities
Dim persons = dc.Members.Where(AddressOf myTest)
count = persons.Count
End Using
System.Diagnostics.Debugger.Break()
End Sub
Function myTest(ByVal m As Member) As Boolean
Return m.ID = "100" AndAlso m.Roles.Select(AddressOf myRoleTest).Count > 0
End Function
Function myRoleTest(ByVal r As Role) As Boolean
Return r.Name = "Member"
End Function
SQL Profiler показывает это:
SQL: BatchStarting
SELECT
[Extent1].[ID] AS [ID],
... (all columns from Members snipped for brevity) ...
FROM [dbo].[Members] AS [Extent1]
RPC: завершено
exec sp_executesql N'SELECT
[Extent2].[ID] AS [ID],
[Extent2].[Name] AS [Name],
[Extent2].[Active] AS [Active]
FROM [dbo].[RoleMembership] AS [Extent1]
INNER JOIN [dbo].[Roles] AS [Extent2] ON [Extent1].[RoleID] = [Extent2].[ID]
WHERE [Extent1].[MemberID] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=100
SQL: BatchCompleted
SELECT
[Extent1].[ID] AS [ID],
... (all columns from Members snipped for brevity) ...
FROM [dbo].[Members] AS [Extent1]
Я не уверен, почему он использует sp_execsql для внутреннего оператора соединения и почему он все еще выполняет выбор для выбора ВСЕХ членов.
Спасибо.
ОБНОВЛЕНИЕ 2
Я написал это, превратив вышеупомянутые «множественные методы» в лямбда-выражения, а затем все в один запрос, например:
Dim allIDs As String = String.Empty
Using dc As New CBLModel.CBLEntities
For Each retM In dc.Members.Where(Function(m As Member) m.ID = 100 AndAlso m.Roles.Select(Function(r As Role) r.Name = "Doctor").Count > 0)
allIDs &= retM.ID.ToString & ";"
Next
End Using
Но, похоже, это не работает: «Доктор» - это не роль, которая существует, я просто поместил ее для тестирования, но для «allIDs» все еще установлено значение «100;»
SQL в SQL Profiler на этот раз выглядит так:
SELECT
[Project1].*
FROM ( SELECT
[Extent1].*,
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[RoleMembership] AS [Extent2]
WHERE [Extent1].[ID] = [Extent2].[MemberID]) AS [C1]
FROM [dbo].[Members] AS [Extent1]
) AS [Project1]
WHERE (100 = [Project1].[ID]) AND ([Project1].[C1] > 0)
Для краткости я превратил список всех столбцов из таблицы Members в *
Как видите, он просто игнорирует запрос "Роль".