如何使用Linq和实体框架连接两个连接表?

如何使用Linq和实体框架连接两个连接表?,linq,entity-framework,entity-framework-4.1,inner-join,intersection,Linq,Entity Framework,Entity Framework 4.1,Inner Join,Intersection,我有一个非常规范化的数据库,我正在尝试将两个连接表连接在一起 我的目标是只显示用户有权访问的文档。我使用的是实体框架,并为下表设置了几个外键: 关系(外键) 表格定义 public partial class Users : EntityObject { public int UserID {get;set;} //PK public string UserDisplayName {get;set;} public DateTime CreateDate {get

我有一个非常规范化的数据库,我正在尝试将两个连接表连接在一起

我的目标是只显示用户有权访问的文档。我使用的是实体框架,并为下表设置了几个外键:

关系(外键)

表格定义

public partial class Users : EntityObject  
{
    public int UserID {get;set;} //PK
    public string UserDisplayName {get;set;}  
    public DateTime CreateDate {get;set;} 
    public DateTime LoginDate {get;set;}  
} 

public partial class Groups : EntityObject  
{
    public int GroupID {get;set;} //PK
    public string GroupDisplayName {get;set;}  
    public DateTime CreateDate {get;set;} 
    public DateTime LoginDate {get;set;}  
} 


public partial class UserGroupMembership: EntityObject  // JoinTable
{
   public int UserID {get;set;} //PK
   public int GroupID {get;set;} //PK

   // Not sure if this extra columns below causes an issue
   public bool CanView {get;set;}
   public bool CanDelete {get;set;} 
   public bool CanUpdate {get;set;} 
   public DateTime CreateDate {get;set;}   
}

public partial class XDocumentSecurity : EntityObject // JoinTable
{
    public int DocumentID {get;set;} //FK
    public int GroupID {get;set;} //FK

     public DateTime CreateDate {get;set;}   // Not sure if this extra column causes an issue  
 } 

public partial class XDocuments : EntityObject  
{
    public int DocumentID {get;set;} //PK
    public string URL {get;set;}  
    public DateTime CreateDate {get;set;} 
} 
我听说过很多关于Linq to EF如何以一种性能次优的方式改变SQL查询的故事

这似乎是最适合我所做的。我可以简单地获取当前用户所属组的列表,并发布此查询的修改版本:

public void Linq50() 
{ 
    int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 }; 
    int[] numbersB = { 1, 3, 5, 7, 8 }; 

    var commonNumbers = numbersA.Intersect(numbersB); 

    Console.WriteLine("Common numbers shared by both arrays:"); 
    foreach (var n in commonNumbers) 
    { 
        Console.WriteLine(n); 
    } 
}
问题

  • 如何查看EF生成的SQL查询
  • 解决此问题的更好方法是什么(如果有)

如果您的所有键和外键都具有导航属性,则不带
Intersect
的替代查询将是:

var query = context.XDocuments
    .Where(d => d.Groups.Any(g => g.Users.Any(u => u.UserID == givenUserId)));
(“筛选至少一个组中的所有文档,该组中至少有一个用户使用key=
givenUserId
”)

我不知道这在性能方面是否会更好

在EF 4.1中,您只需通过以下方式检查生成的SQL:

var sql = query.ToString();
编辑

我对您的模型外观的理解如下:

具有相应表格的三个实体:

public class User
{
    public int UserID { get; set; }
    public ICollection<Group> Groups { get; set; }
}

public class Group
{
    public int GroupID { get; set; }
    public ICollection<User> Users { get; set; }
    public ICollection<XDocument> Documents { get; set; }
}

public class XDocument
{
    public int DocumentID { get; set; }
    public ICollection<Group> Groups { get; set; }
}

在这个模型中,应该可以映射上面描述的查询。无需直接访问联接表(并且您实际上无法通过LINQ访问实体,EF在内部管理这些表)。

您还可以使用以下任一方法查看EF 4.1生成的SQL

  • SQL分析器
不过,此时,您需要使用EF 4.1的

关于你的第二个问题,我相信你的提问可以很好地解释。使用LINQPad检查SQL,下面的查询

var a1 = Addresses.Where(a => a.City.ToUpper().EndsWith("L")).Select(a => a.AddressID);
var a2 = Addresses.Where(a => a.City.ToUpper().StartsWith("B")).Select(a => a.AddressID);

var x1 = a1.Intersect(a2);
转化为

SELECT 
[Intersect1].[AddressID] AS [C1]
FROM  (SELECT 
    [Extent1].[AddressID] AS [AddressID]
    FROM [Person].[Address] AS [Extent1]
    WHERE UPPER([Extent1].[City]) LIKE N'%L'
INTERSECT
    SELECT 
    [Extent2].[AddressID] AS [AddressID]
    FROM [Person].[Address] AS [Extent2]
    WHERE UPPER([Extent2].[City]) LIKE N'B%') AS [Intersect1]

我认为@Slauma建议使用导航程序,如果您的模型支持的话,这是一个不错的选择


尽管如此,获取LINQPad-你不会后悔的:)

我想我已经被洗脑,认为这是从c中选择数据的唯一方法:
,其中c.UserID==UserID.Value选择c我会试试你的技巧,谢谢!隐马尔可夫模型;XDocumentSecurity的引用在哪里?这是我真正被卡住的部分on@makerofthings7:我假设
XDocumentSecurity
XDocuments
之间的联接表,因为复合PK和两个FK(在
Group
XDocument
实体和
XDocumentSecurity
之间的多对多关系不是一个实体,只是一个联接表)。这是错误的吗?您能否在问题中显示您拥有的实体类及其导航属性。我有两个联接表,它们联接其他表。我添加了一个“图形”@makerofthings7:那个么在查询中就根本不需要使用
XDocumentSecurity
。请看我上面的编辑,我已经尝试澄清了这一点。可以通过
Intersect
在一个查询中加载文档,而不是只加载ID(与第一个代码段大致相同:)。这也可以说是LINQ或导航属性友好。但我真的不知道SQL性能方面有什么更好。我也觉得Where Any更适合大表,但我肯定不是。哦,在您编辑之后,我现在很困惑。为什么不
XDocumentSecurity.GroupID
参考
Groups.GroupID
而不是
UserGroupMembership.GroupID
?我想知道如何在SQL中定义它,因为这种关系中没有(完整的)主键或唯一列(至少在SQL Server中是必需的)@Slauma-没错,我更正了FK图。什么是
EntityObject
?是您自己的基类还是EF的EntityObject类?我想知道,因为您的问题被标记为EF 4.1。如果您使用的是
DbContext
,那么您无法从EF的
EntityObject
派生。是的,中的附加列如果要定义多对多关系,则连接表是一个问题。基本上,您必须为每个多对多创建两个一对多关系。最后一个问题:为什么您的模型没有任何导航属性来定义实体之间的关系?@Slauma EntityObject来自EF。我不是首先使用代码,而是直接使用模型。没有存储库或类似的东西。我正在查看向导生成的对象。同时,我意识到我的安装可能不是EF的最新版本,因此我更新为EF 4.1 Update 1。有导航属性,我会将它们添加到问题中。此练习帮助我提前了解我需要什么在将来问一个EF问题。
var a1 = Addresses.Where(a => a.City.ToUpper().EndsWith("L")).Select(a => a.AddressID);
var a2 = Addresses.Where(a => a.City.ToUpper().StartsWith("B")).Select(a => a.AddressID);

var x1 = a1.Intersect(a2);
SELECT 
[Intersect1].[AddressID] AS [C1]
FROM  (SELECT 
    [Extent1].[AddressID] AS [AddressID]
    FROM [Person].[Address] AS [Extent1]
    WHERE UPPER([Extent1].[City]) LIKE N'%L'
INTERSECT
    SELECT 
    [Extent2].[AddressID] AS [AddressID]
    FROM [Person].[Address] AS [Extent2]
    WHERE UPPER([Extent2].[City]) LIKE N'B%') AS [Intersect1]