2010-02-24 7 views
2

Essayer d'apprendre la syntaxe Linq et je suis aux prises avec des expressions basées sur des méthodes. J'ai 8 tables qui permettent aux utilisateurs de s'associer à des groupes et des organisations et ont des formes associées à des groupes. Pour plus d'explications, j'assigne un formulaire à un groupe. Ce groupe peut avoir un utilisateur assigné directement ou via une organisation à laquelle l'utilisateur appartient. J'ai besoin d'une instruction Linq qui rejoindra/union correctement les tables afin que je puisse retourner les formulaires assignés à un utilisateur donné. Voici le schéma de base:Linq to Entities Aide à la jointure et à l'union

Modifier le 25 février
1. Notez que je utilise VS2010 et compilation 4.0.
2. Suppression de la colonne pk id de toutes les tables de liens et activation de 'Include foreign key columns' dans l'assistant, qui nettoyait la disposition edmx (les tables de liens définissaient désormais les ensembles d'entité)
3. Ajout de scripts de table (extraits de certains duvet) et a ajouté le edmx comme généré par le designer
4. Réécriture mon t-sql d'utiliser IN clause EXISTS, fonctionne toujours
5. toujours lire et tester edmx avec LINQPad, soupir ...

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

L'instruction T-SQL moche qui me donne ce que je veux est:

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) 
) 

S'il vous plaît et merci! Etes-vous sûr de vouloir utiliser autant de tables?

+0

Jetez un coup d'œil à LinqPad – Zyphrax

+0

Oui, je me suis baladé avec LinqPad et je n'ai pas encore trébuché sur la bonne combinaison. Merci. Je viens de m'inscrire ici donc je ne peux pas encore créer de lien vers un jpg de mon edmx .... – Andy

Répondre

1

Trifouiller LINQPad, je suis quelque chose qui a fonctionné! Je me sens assez épais pour l'instant car les concepts sont encore flous. Ce qui m'a aidé était de jeter les clés primaires sur les tables de liens. Une meilleure façon d'écrire cette requête? À quoi cela ressemblerait-il en utilisant des méthodes?

convertisseur de résultat de LINQPad (le symbole lambda) crache sur:

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() 

qui semble un terrible gâchis ...

et le résultat sql de LINQPad est:

-- 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] 

qui lors de son exécution contre db donne les bons résultats aussi bien ...

0


Etes-vous sûr de toutes les relations N: N?

Je n'ai pas SQL Management Studio ici (je suis sur mon mac). Mais je suppose que vous pouvez simplifier votre déclaration 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 

Cela devrait faciliter la construction de votre déclaration LINQ.
Voici quelques informations utiles sur LINQ et externe gauche/inner join dans 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

Merci pour la réponse et les liens. J'ai parcouru les 101 Echantillons pendant mes luttes sans succès. Votre requête ci-dessus omet des données. Je joue toujours avec, mais je pense que j'ai besoin de la structure de la table comme décrit, mais je serais heureux d'avoir d'autres corrections. Pour réaffirmer, un utilisateur peut être membre d'un groupe et d'une organisation. Une organisation peut également appartenir à un groupe. Les formulaires sont affectés uniquement à des groupes (groupe_formulaire), ce qui permet à un utilisateur d'avoir des formulaires soit par la relation directe utilisateur_groupe, soit par la relation org_utilisateur -> org -> org_groupe. – Andy