我正在尝试查询一对多关系,但无法弄清楚如何做到这一点。我遇到的问题是我要过滤的字段的 ID 存在于连接表(不是主表)中......
它可能更容易说明而不是解释!
我的两门课是
public class DbUserClient
{
public virtual string UserId { get; set; }
public virtual int ClientId { get; set; }
public virtual DateTime AssignedOn { get; set; }
public virtual DateTime? ClearedOn { get; set; }
// navigation properties
public virtual DbUser User { get; set; }
public virtual DbClient Client { get; set; }
}
和
public class DbClient
{
public virtual int ClientId {get;set;}
public virtual string EntityName { get; set; }
public virtual bool Deleted { get; set; }
// navigation properties
public ICollection<DbUserClient> UserClients { get; set; }
}
在程序中,我有一个暴露客户端的存储库,即
public ObservableCollection<DbClient> Clients
{
get { return context.Clients.Local; }
}
我对此绑定,这就是为什么我热衷于通过客户端查询,因为这将刷新我的“本地”集合。但是,我似乎无法找到一种方法来包含 UserClients 以及添加“where”子句。
我尝试过类似的东西
context.Clients.Include(c => c.UserClients.Where(uc => uc.UserId == "ME"));
但这会导致以下异常“包含路径表达式必须引用在类型上定义的导航属性。使用虚线路径作为引用导航属性,使用 Select 运算符作为集合导航属性。参数名称:路径”
这可行,但不幸的是不会更新我的“本地”收藏
from c in context.Clients
from uc in c.UserClients
where uc.ClientId == uc.ClientId && uc.UserId == "ME"
select new { c.ClientId, c.EntityName, uc.AssignedOn };
关于我哪里出错的任何建议?
干杯腹肌
编辑我:查看 SQL Profiler 上面的查询生成以下 SQL
SELECT
[Extent1].[ClientId] AS [ClientId],
[Extent1].[EntityName] AS [EntityName],
[Extent2].[AssignedOn] AS [AssignedOn]
FROM [dbo].[Client] AS [Extent1]
INNER JOIN [dbo].[UserClient] AS [Extent2] ON [Extent1].[ClientId] = [Extent2]. [ClientId]
WHERE ([Extent2].[ClientId] = [Extent2].[ClientId]) AND (N'ME' = [Extent2].[UserId])
这非常简单,或多或少类似于我自己编写 SQL 时会写的内容
但是,尽管下面建议的表达式有效并且正如您指出的那样填充了本地缓存
context.Clients
.Where(c => c.UserClients.Any(uc => uc.UserId == userId))
.Select(c => new { DbClient = c, DbUser = c.UserClients.Where(uc => uc.UserId == userId).FirstOrDefault() }).ToList();
它产生以下 SQL。这看起来比它需要的复杂得多,我假设这会对性能产生影响
exec sp_executesql N'SELECT
[Filter2].[ClientId] AS [ClientId],
[Filter2].[EntityName] AS [EntityName],
[Filter2].[Deleted] AS [Deleted],
[Limit1].[UserId] AS [UserId],
[Limit1].[ClientId] AS [ClientId1],
[Limit1].[AssignedOn] AS [AssignedOn],
[Limit1].[ClearedOn] AS [ClearedOn]
FROM (SELECT [Extent1].[ClientId] AS [ClientId], [Extent1].[EntityName] AS [EntityName], [Extent1].[Deleted] AS [Deleted]
FROM [dbo].[Client] AS [Extent1]
WHERE EXISTS (SELECT
1 AS [C1]
FROM [dbo].[UserClient] AS [Extent2]
WHERE ([Extent1].[ClientId] = [Extent2].[ClientId]) AND ([Extent2].[UserId] = @p__linq__0)
) ) AS [Filter2]
OUTER APPLY (SELECT TOP (1)
[Extent3].[UserId] AS [UserId],
[Extent3].[ClientId] AS [ClientId],
[Extent3].[AssignedOn] AS [AssignedOn],
[Extent3].[ClearedOn] AS [ClearedOn]
FROM [dbo].[UserClient] AS [Extent3]
WHERE ([Filter2].[ClientId] = [Extent3].[ClientId]) AND ([Extent3].[UserId] = @p__linq__1) ) AS [Limit1]',N'@p__linq__0 nvarchar(4000),@p__linq__1 nvarchar(4000)',@p__linq__0=N'ME',@p__linq__1=N'ME'
编辑二:在玩了一些之后,我找到了一个似乎满足我要求的解决方案。查看 SQL Profiler,我对生成的 SQL 感到满意。这与我的原始查询类似。
exec sp_executesql N'SELECT
[Extent1].[ClientId] AS [ClientId],
[Extent1].[EntityName] AS [EntityName],
[Extent1].[Deleted] AS [Deleted],
[Extent2].[UserId] AS [UserId],
[Extent2].[ClientId] AS [ClientId1],
[Extent2].[AssignedOn] AS [AssignedOn],
[Extent2].[ClearedOn] AS [ClearedOn]
FROM [dbo].[Client] AS [Extent1]
INNER JOIN [dbo].[UserClient] AS [Extent2] ON [Extent1].[ClientId] = [Extent2].[ClientId]
WHERE [Extent2].[UserId] = @p__linq__0',N'@p__linq__0 nvarchar(4000)',@p__linq__0=N'ME'
我假设这里没有延迟加载。如果有人可以确认我将不胜感激
context.Clients.Join
(
context.UserClients,
c => c.ClientId,
uc => uc.ClientId,
(user, usrclient) => new { DbClient = user, DbUserClient = usrclient }
).Where(uc => uc.DbUserClient.UserId == userId).Load();