Linq to Entities加入/联盟声明帮助

时间:2010-02-24 17:16:29

标签: linq-to-entities

尝试学习Linq语法并且正在努力学习基于方法的vs表达式。我有8个表,允许用户关联到组和组织,并具有与组关联的表单。为了进一步解释,我将一个表单分配给一个组。该组可以直接或通过用户所属的组织分配用户。我需要一个Linq语句,它将正确地连接/联合表,以便我可以返回分配给给定用户的表单。这是基本架构:

编辑2月25日 1.注意我正在使用VS2010并编译4.0 2.从所有链接表中删除了pk id列,并在向导中启用了“包含外键列”,这清理了edmx布局(链接表现在关联设置副实体集)
3.添加了表脚本(剪掉了一些绒毛)并添加了由设计者生成的edmx 4.将我的t-sql从使用IN子句重写为EXISTS,仍然可以工作 5.仍在用LinqPad阅读和测试edmx,感叹......

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 个答案:

答案 0 :(得分: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的结果转换器(lambda符号)吐出:

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

看起来很乱......

和LinqPad的sql结果是:

-- 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运行时,也会产生正确的结果......

答案 1 :(得分:0)

你确定你需要那么多桌子吗? 你确定所有的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