2010-02-24 2 views
2

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

Редактировать 25 фев.
1. Примечание. Я использую VS2010 и компилирую 4.0.
2. Удален столбец pk id из всех таблиц ссылок и включен «Включить столбцы внешнего ключа» в мастере, который очистил макет edmx (теперь в таблицах ссылок теперь установлены ассоциации наборов наборы сущностей)
3. Добавлены скрипты таблиц (вырезаны некоторые пуха) и добавил EDMX, сгенерированный дизайнером
4. переписаны мой T-SQL с использованием в пункте для 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) 
) 

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

+0

Отъезд LinqPad – Zyphrax

+0

Да, я общался с LinqPad и еще не наткнулся на правильную комбинацию. Благодарю. Я только что зарегистрировался здесь, поэтому я не могу ссылаться на jpg моего edmx еще .... – Andy

ответ

1

возился с 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

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

У меня нет студия управления SQL здесь (я нахожусь на своем 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

+0

Спасибо за ответ и ссылки. Проанализировали 101 образец во время моей борьбы без успеха. Ваш запрос выше опускает данные. Я все еще играю с этим, но я думаю, что мне нужна структура таблицы, как описано, но будет приветствовать дальнейшую коррекцию. Для повторного использования пользователь может быть членом как группы, так и организации. Орг может также принадлежать группе. Формы присваиваются только группам (form_group), поэтому пользователь может иметь формы либо прямым отношением user_group, либо отношением org_user -> org -> org_group. – Andy