I have a very normalized database, and I\'m trying to join two join tables together.
My goal is to only show documents that the user has permission to. I\'m using Ent
If you have navigation properties for all your keys and foreign keys an alternative query without an Intersect
would be:
var query = context.XDocuments
.Where(d => d.Groups.Any(g => g.Users.Any(u => u.UserID == givenUserId)));
("Filter all documents which are in at least one group which has at least one user with the key = givenUserId
")
I don't know if this will be better with respect to performance.
In EF 4.1 you can inspect the generated SQL simply by:
var sql = query.ToString();
Edit
My understanding how your model would look is the following:
Three entities with corresponding tables:
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; }
}
And between User
and Group
a many-to-many relationship and between Group
and XDocument
as well:
modelBuilder.Entity<User>()
.HasMany(u => u.Groups)
.WithMany(g => g.Users)
.Map(c =>
{
c.MapLeftKey("UserID");
c.MapRightKey("GroupID");
c.ToTable("UserGroupMembership"); // join table name, no entity
});
modelBuilder.Entity<XDocument>()
.HasMany(d => d.Groups)
.WithMany(g => g.Documents)
.Map(c =>
{
c.MapLeftKey("DocumentID");
c.MapRightKey("GroupID");
c.ToTable("XDocumentSecurity"); // join table name, no entity
});
In this model and mapping the query described above should be possible. There is no need to access the join tables directly (and you can't actually access them via LINQ to Entities, EF manages those tables internally).
You can also view the SQL generated by EF 4.1 using either
Although, at this time, you need to use the LINQPad beta for EF 4.1.
Regarding your second question, I believe your query would translate fine. Using LINQPad to check the SQL, the following query
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);
translates to
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]
I think @Slauma's recommendation to use navigation proeprties is the way to go if your model supports it.
Still, get LINQPad - you won't regret it :)