2013-10-12 3 views
1

많은 게시물을 보았지만 내 질문에 대한 답변 1 개를 찾지 못했습니다. 저는 LINQ에 익숙하지 않아서 매우 간단하다고 생각합니다. 나는 그것을 얻지 못하고 있습니다.개체의 IQueryable 컬렉션을 반환하는 간단한 LINQ 조인

나는이 간단한 개체가 다음과 같이 주소와 국가, 정의를 :

public class Address 
{ 
    [Key] 
    public int Id { get; set; } 
    public string CityName { get; set; } 
    public int? StateId { get; set; } 
    [ForeignKey("StateId")] 
    public virtual State State { get; set; } 
} 


public class State 
{ 
    [Key] 
    public int Id { get; set; } 
    public string StateName { get; set; } 
} 

내가 주소의 된 IQueryable을 반환한다 할 노력하고있어,하지만 난 SQL 왼쪽의 동등하고 싶은 모든 외부 조인을하고 StateName을 Address에 반환합니다.

"I"로 시작하는 도시가있는 Addresses를 반환합니다. 이것은 잘 작동합니다. State 테이블에 가입하고 StateName을 가져와야합니다.

[HttpGet] 
public IQueryable<Address> Addresses() 
{ 
    var query = from a in _contextProvider.Context.Addresses 
    where a.CityName.StartsWith("I") 
    select a; 
    return query; 
} 

답변

1

주소 클래스에는 이미 관계를 나타내는 State 속성이 있습니다. 왜 그냥 사용하지 않니?

public IQueryable<string> Addresses() 
{ 
    var query = from a in _contextProvider.Context.Addresses 
       where a.CityName.StartsWith("I") 
       select a.State.StateName; 

    return query; 
} 


업데이트 : 최신 코멘트에서

내가 false로 LazyLoadingEnabled을 설정하여 모델에 대한 게으른 로딩을 해제 같아요. 기본적으로 lazy loading이 가능합니다. 이전 버전의 EF는 lazy loading을 지원하지 않았기 때문에 다소 혼란 스러울 수 있습니다.

지연로드를 비활성화하면 명시 적로드가 "활성화"되고 관련 개체를 명시 적으로로드해야합니다.

var query = from a in _contextProvider.Context.Addresses.Include("State") 
      where a.CityName.StartsWith("I") 
      select a; 

또는 (최종 쿼리를 수정) 쿼리에 관련된 속성에 액세스 : 귀하의 경우에 당신은 (이것은 열망로드라고합니다)를 Include 방법을 사용하여이 작업을 수행 할 수 있습니다

var states = (from a in Addresses() // Addresses is your query method 
       select a.State).ToList(); 

을 두 번째 버전에서는 linq-to-entities가 쿼리에서 액세스하기 때문에 상태가 자동으로 포함됩니다. Addresses 메서드는 IQueryable을 반환하므로 실제로 열거되기 전에 쿼리가 실행되지 않습니다. 따라서 실행 된 SQL 쿼리는 Addresses이 반환 한 쿼리를 사용하는 방법에 따라 달라집니다. 먼저 Addresses 쿼리를 실행하고 나중에 상태를 액세스하는 경우

LINQ - 투 - 엔티티를 포함하지 않습니다

var states = (from a in Addresses().ToList() // <- ToList() executes the query before states are accessed 
       select a.State).ToList(); 

게으른 로딩은 종종 데이터베이스에 불필요한 왕복을 방지하기 위해 꺼집니다. 지연로드를 활성화 한 다음 Addresses에 의해 반환 된 쿼리를 즉시 실행하면 관련 객체에 대한 각각의 액세스가 실제로 데이터베이스 쿼리를 생성합니다. 그러나 다시 : 최종 질의에 상태를 포함하면 linq-to-entities는 자동으로 JOIN을 생성하여 (지연로드를 사용하는지 여부와 관계없이)이를 포함시킵니다.

Include을 사용하여 관련 상태를 열심히로드하는 솔루션은 나중에 액세스하지 않아도 괜찮습니다. 그리고 조인을 사용하는 원래 생각도 괜찮습니다. 그러나 당신의 방법이 IQueryable<Address>을 돌려주기를 원하기 때문에, 당신은 콜 사이트에서 그것을해야만합니다.

게으른 로딩을 활성화 한 경험으로 인해 작업이 훨씬 수월해졌습니다.진행 상황을 정확히 모르는 경우 데이터베이스로의 불필요한 왕복이 발생할 수 있습니다. 그러나 여전히 Include을 사용하여 쿼리를 최적화 할 수 있습니다. 더 나은 LINQ 쿼리가 나는 SQL 프로파일 (또는 Express Profiler 같은 무료 도구 당신이 사용하는 경우 SQL Server Express를) 사용하는 것이 좋습니다 SQL 문으로 변환되는 방법을 이해합니다. 또한 통증이있을 수있는 명시 적 로딩을 사용하는 반면에

. 관련 테이블을 모두 포함 시키면 huge datasets이됩니다. 어떤 이유로 당신이 모든 관련 테이블을 포함 할 수없는 경우 당신은 개체가로드되는 경우 명시 적으로 확인해야 : context.Entry(address).Reference(a => a.State).IsLoaded은. Nullable 속성이 null 인 경우 데이터베이스에서 NULL인지 또는 아직로드되지 않았는지 알 수 없습니다.

+0

이렇게하면 변환 오류가 발생합니다 (암시 적으로 'System.Linq.IQueryable '형식으로 'System.Linq.IQueryable '형식으로 변환 할 수 없음). 이유를 이해합니다. 상태 이름뿐 아니라 모든 주소 필드를 원합니다. 명시 적으로 나열해야합니까? 그런 다음 그것을 던져야합니까? 감사합니다 – mwill

+0

@mwill : 나는'된 IQueryable '에 반환 형식을 변경했습니다. 모든 주소 필드를 가져 오려면 코드가 완벽하게 괜찮습니다. JOIN은 State 속성의 ForeignKey 특성을 통해 이미 수행됩니다. – pescolino

+0

예, 모든 주소 입력란을 원합니다. 내 원래 코드에서 State는 NULL이므로 직접 join을 작성해야한다고 생각했습니다. 어딘가에 놓친 것 같은데? 덕분에 – mwill