Linq to Entities Присоединиться / Помощь Союз Заявление - PullRequest
1 голос
/ 24 февраля 2010

Пытаюсь выучить синтаксис Linq и борюсь с выражениями на основе методов. У меня есть 8 таблиц, которые позволяют пользователям связываться с группами и организациями и имеют формы, связанные с группами. Для дальнейшего объяснения я назначаю форму группе. Этой группе может быть назначен пользователь напрямую или через организацию, к которой он принадлежит. Мне нужен оператор Linq, который будет правильно объединять / объединять таблицы, чтобы я мог возвращать формы, назначенные данному пользователю. Вот основная схема:

Редактировать 25 февраля
1. Обратите внимание, что я использую VS2010 и компилирую 4.0.
2. Убрал столбец pk id из всех таблиц ссылок и включил «Включить столбцы внешнего ключа» в мастере, который очистил макет edmx (теперь таблицы ссылок связаны с наборами наборов вице-сущностей)
3. Добавлены табличные скрипты (вырвано немного пуха) и добавлен edmx, сгенерированный дизайнером
4. Переписал мой t-sql с использования предложения IN на EXISTS, все еще работает
5. Еще читаю и тестирую edmx с LinqPad, вздох ...

CREATE TABLE [dbo].[Org](
[orgID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](100) NULL,
CONSTRAINT [PK_Org] PRIMARY KEY CLUSTERED 
(
[orgID] ASC
) 

CREATE TABLE [dbo].[Groups](
[groupID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NOT NULL,
CONSTRAINT [PK_Group] PRIMARY KEY CLUSTERED 
(
[groupID] ASC
)

CREATE TABLE [dbo].[Form](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](100) NULL,
CONSTRAINT [PK_Form] PRIMARY KEY CLUSTERED 
(
[ID] ASC
)

CREATE TABLE [dbo].[Users](
[userID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NOT NULL,
CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED 
(
[userID] ASC
)

###############################################################
Link tables and FKs
###############################################################

CREATE TABLE [dbo].[User_Org](
[userID] [int] NOT NULL,
[orgID] [int] NOT NULL)

ALTER TABLE [dbo].[User_Org]  WITH CHECK ADD  CONSTRAINT [FK_User_Org_Org] FOREIGN KEY([orgID])
REFERENCES [dbo].[Org] ([orgID])

ALTER TABLE [dbo].[User_Org] CHECK CONSTRAINT [FK_User_Org_Org]

ALTER TABLE [dbo].[User_Org]  WITH CHECK ADD  CONSTRAINT [FK_User_Org_Users] FOREIGN KEY([userID])
REFERENCES [dbo].[Users] ([userID])

ALTER TABLE [dbo].[User_Org] CHECK CONSTRAINT [FK_User_Org_Users]

###############################################################
CREATE TABLE [dbo].[User_Group](
[userID] [int] NOT NULL,
[groupID] [int] NOT NULL)

ALTER TABLE [dbo].[Org_Group] CHECK CONSTRAINT [FK_Org_Group_Org]

ALTER TABLE [dbo].[User_Group]  WITH CHECK ADD  CONSTRAINT [FK_User_Group_Group] FOREIGN KEY([groupID])
REFERENCES [dbo].[Groups] ([groupID])

ALTER TABLE [dbo].[User_Group] CHECK CONSTRAINT [FK_User_Group_Group]

ALTER TABLE [dbo].[User_Group]  WITH CHECK ADD  CONSTRAINT [FK_User_Group_Users] FOREIGN KEY([userID])
REFERENCES [dbo].[Users] ([userID])

ALTER TABLE [dbo].[User_Group] CHECK CONSTRAINT [FK_User_Group_Users]

###############################################################
CREATE TABLE [dbo].[Org_Group](
[orgID] [int] NOT NULL,
[groupID] [int] NOT NULL)

ALTER TABLE [dbo].[Org_Group]  WITH CHECK ADD  CONSTRAINT [FK_Org_Group_Group] FOREIGN KEY([groupID])
REFERENCES [dbo].[Groups] ([groupID])

ALTER TABLE [dbo].[Org_Group] CHECK CONSTRAINT [FK_Org_Group_Group]

ALTER TABLE [dbo].[Org_Group]  WITH CHECK ADD  CONSTRAINT [FK_Org_Group_Org] FOREIGN KEY([orgID])
REFERENCES [dbo].[Org] ([orgID])

###############################################################
CREATE TABLE [dbo].[Form_Group](
[FormID] [int] NOT NULL,
[groupID] [int] NOT NULL)

ALTER TABLE [dbo].[Form_Group]  WITH CHECK ADD  CONSTRAINT [FK_Form_Group_Form] FOREIGN KEY([FormID])
REFERENCES [dbo].[Form] ([ID])

ALTER TABLE [dbo].[Form_Group] CHECK CONSTRAINT [FK_Form_Group_Form]

ALTER TABLE [dbo].[Form_Group]  WITH CHECK ADD  CONSTRAINT [FK_Form_Group_Groups] FOREIGN KEY([groupID])
REFERENCES [dbo].[Groups] ([groupID])

ALTER TABLE [dbo].[Form_Group] CHECK CONSTRAINT [FK_Form_Group_Groups]

alt text

Паршивое утверждение T-SQL, которое дает мне то, что я хочу:

declare @userid int
set @userid = 1
select distinct(f.id)
from Form f
join Form_Group fg on f.id = fg.formid 
join Groups g on fg.groupid = g.groupid
where exists
((select g1.groupid
from Groups g1 
join User_Group ug on g1.groupid = ug.groupid 
join Users u on ug.userid = u.userid
where u.userid = @userid
and g.groupid = g1.groupid)
union
(select g2.groupid
from Groups g2 
join Org_group og on g2.groupid = og.groupid 
join Org o on og.orgid = o.orgid 
join User_org uo on o.orgid = uo.orgid 
join Users u on uo.userid = u.userid
where u.userid = @userid
and g.groupid = g2.groupid)
) 

Пожалуйста и спасибо!

Ответы [ 2 ]

1 голос
/ 25 февраля 2010

Возиться с LinqPad, у меня получилось то, что сработало!

int userID = 1;  

var formIDsforUser = 
(from g in Groups
from u in g.Users 
where u.userID == userID 
from o in g.Orgs 
from u1 in o.Users 
where u.userID == userID
from f in g.Form
select f.ID).Distinct();

В данный момент я чувствую себя довольно бестолково, так как понятия все еще размыты. Думаю, мне помог сбросить первичные ключи в таблицах ссылок. Есть ли лучший способ написать этот запрос? Как бы это выглядело при использовании методов?

Преобразователь результатов LinqPad (лямбда-символ) выплевывает:

Group.MergeAs (AppendOnly)
.SelectMany (
  g => g.Users, 
  (g, u) => 
     new  
     {
     }
)
.Where (temp0 => (temp0.u.userID == userID))
.SelectMany (
  temp0 => temp0.g.Orgs, 
  (temp0, o) => 
     new  
     {
     }
)
.SelectMany (
  temp1 => temp1.o.Users, 
  (temp1, u1) => 
     new  
     {
     }
)
.Where (
  temp2 => 
     (temp2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.u.userID == userID)
)
.SelectMany (
  temp2 => temp2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.g.Form, 
  (temp2, f) => f.ID
)
.Distinct ()

что выглядит ужасно ...

и результат sql для LinqPad:

-- Region Parameters  
DECLARE p__linq__0 Int = 1  
DECLARE p__linq__1 Int = 1  
-- EndRegion  
SELECT   
[Distinct1].[formID] AS [formID]  
FROM ( SELECT DISTINCT   
[Extent4].[formID] AS [formID]  
FROM    (SELECT   
  [User_Group].[userID] AS [userID],   
  [User_Group].[groupID] AS [groupID]  
  FROM [dbo].[User_Group] AS [User_Group]) AS [Extent1]  
INNER JOIN (SELECT   
  [Org_Group].[orgID] AS [orgID],   
  [Org_Group].[groupID] AS [groupID]  
  FROM [dbo].[Org_Group] AS [Org_Group]) AS [Extent2]  
      ON [Extent1].[groupID] = [Extent2].[groupID]  
INNER JOIN (SELECT 
  [User_Org].[userID] AS [userID], 
  [User_Org].[orgID] AS [orgID]
  FROM [dbo].[User_Org] AS [User_Org]) AS [Extent3]  
         ON [Extent2].[orgID] = [Extent3].[orgID]
INNER JOIN (SELECT 
  [Form_Group].[formID] AS [formID], 
  [Form_Group].[groupID] AS [groupID]
  FROM [dbo].[Form_Group] AS [Form_Group]) AS [Extent4]  
        ON [Extent1].[groupID] = [Extent4].[groupID]
WHERE ([Extent1].[userID] = @p__linq__0) 
       AND ([Extent1].[userID] = @p__linq__1)  
)  AS [Distinct1]

, который при запуске против db также дает надлежащие результаты ...

0 голосов
/ 24 февраля 2010

Вы уверены, что вам нужно столько таблиц?
Вы уверены во всех отношениях N: N?

У меня нет SQL Management Studio здесь (я на моем Mac). Но я думаю, вы могли бы упростить свой оператор T-SQL до:

select distinct(Form.id)
from Form
     inner join Form_Group on Form.formID = Form_Group.formID
     inner join Group on Form_Group.groupID = Group.groupID
     left outer join User_Group on Group.groupid = User_Group.groupid AND User_Group.userid = @userid  
     left outer join Org_Group on Group.groupid = Org_Group.groupid   
     inner join Org on Org_Group.orgid = Org.orgid   
     inner join User_Org on Org.orgid = User_Org.orgid AND User_Org.userid = @userid

Это должно упростить построение вашего оператора LINQ.
Вот некоторая полезная информация о LINQ и оставленных внешних / внутренних соединениях в LINQ:

http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx
http://odetocode.com/Blogs/scott/archive/2008/03/25/inner-outer-lets-all-join-together-with-linq.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...