2012-06-27 3 views
1

일대 다 관계를 쿼리하려고하지만이를 수행하는 방법을 찾을 수 없습니다. 내가 가지고있는 문제는 조인 테이블 (기본 테이블이 아님)에 살고 싶은 필드의 ID입니다 ...EF 4.3 코드 첫 번째 - 탐색 속성 뒤로 쿼리

설명하기보다는 설명하기가 쉽습니다 !! 내가 가진

두 클래스는 내가 노출하는 저장소는 클라이언트가 I이 결합을하고

public ObservableCollection<DbClient> Clients 
    { 
     get { return context.Clients.Local; } 
    } 

을 즉 한

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; } 
} 

있는 이것이 "로컬"컬렉션을 새로 고침하기 때문에 클라이언트를 통해 쿼리하는 데 열중하고 있습니다. 그러나 나는 "Where"절을 추가 할뿐만 아니라 UserClients를 포함하는 방법을 찾아 낼 수 없다.

context.Clients.Include 같은

내가 시도 뭔가 (C => c.UserClients.Where (UC => uc.UserId == "ME")); .

그러나 이것은 다음과 같은 예외 결과 "(가) 포함 경로 표현 유형에 정의 된 탐색 속성을 참조 참조 탐색 속성과 컬렉션을 탐색 속성에 대한 선택 운영자 점 경로를 사용합니다 매개 변수 이름을 :. 경로를 "

이 작동하지만, 불행히도 내 업데이트되지 않습니다"로컬 "모음 내가 잘못 갔을 경우에

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 }; 

어떤 제안?

건배 복근

편집 I : 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을 생성 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' 

EDIT II를해야합니다 가정입니다보다이 많이 더 복잡 보인다. SQL 프로파일 러를 살펴보면 생성 된 SQL에 만족합니다. 이는 원래 검색어와 유사합니다.

여기에 관련된 지연로드가 없다고 가정합니다.

var clients = context.Clients 
    .Where(c => c.UserClients.Any(uc => uc.UserId == "ME")) 
    .ToList(); 

이 올바른 클라이언트를로드하지만 사용자가 포함되어 있지 않습니다 : 누군가가 내가 감사 드리겠습니다 확인할 수 있다면

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

답변

0

당신은 = "ME"UserId 적어도 하나의 사용자가 클라이언트를로드 할 수 있습니다 .

당신이 사용자를 포함하는 경우

...
var clients = context.Clients.Include(c => c.UserClients) 
    .Where(c => c.UserClients.Any(uc => uc.UserId == "ME")) 
    .ToList(); 

... 당신은 제대로 필터링 클라이언트를 얻을 수 있습니다하지만 모든 사용자뿐만 아니라 사용자가 "ME"를 포함한다. 당신이 ( ClientUser)를 전체 개체를로드하기 때문에

var clientsWithUser = context.Clients 
    .Where(c => c.UserClients.Any(uc => uc.UserId == "ME")) 
    .Select(c => new 
    { 
     Client = c, 
     User = c.UserClients.Where(uc => uc.UserId == "ME").FirstOrDefault() 
    }) 
    .ToList(); 

이 또한 Local 수집을 업데이트해야합니다 : 마지막 접근 방식, 투사가 가장 좋은 방법입니다뿐만 아니라 필터링 된 사용자를 얻기 위하여

익명 객체 목록에 있습니다.

편집

당신이 탐색 속성이 때 수동으로 가입 쓸 수있는 EF의 방법은 정말로 비록 귀하의 질문의 마지막 쿼리가, 괜찮습니다. 이 쿼리에서

context.UserClients.Include(uc => uc.Client) 
    .Where(uc => uc.UserId == userId) 
    .Load(); 

Include 당신의 손으로 쓴 LINQ Join가 생산하는 같은 INNER JOIN로 번역해야 다음 SQL 쿼리 결과는 대부분 동일하다.

+0

시간을내어 주셔서 감사합니다. 내가 가장 좋은 방법은 내 원래 게시물에 수정 섹션을 추가 한 제안에 대한 의견을 말할 수 있는지 아니었다. 당신이 그것을 들여다 볼 수 있다면 제게 당신의 생각을 알려주세요. – user1460473

+1

@ user1460473 : 간단한 답을 편집 섹션에 추가했습니다. – Slauma

+0

그냥 완벽 :) – user1460473

관련 문제