2009-07-16 3 views
1

내가 잘 작동하지만, 그것은 생성하는 SQL이 복잡하고 비효율적이기 때문에 내 LINQ 쿼리를 최적화하기 위해 찾고 있어요 ... 기본적으로도움말 LINQ 쿼리

을 최적화하는 데 필요한, 내가 (고객 선택 찾고 CustomerDisplay 개체로) 필요한 제품 (reqdProdId)을 주문하고, 외래 키 CustId와 RegisteredCustomer 테이블의 행으로 저장 신용 카드 번호() 개요로

var q = from cust in db.Customers 
     join regCust in db.RegisteredCustomers on cust.ID equals regCust.CustId 
     where cust.CustomerProducts.Any(co => co.ProductID == reqdProdId) 
     where regCust.CreditCardNumber != null && regCust.Authorized == true 
     select new CustomerDisplay 
      { 
       Id = cust.Id, 
       Name = cust.Person.DisplayName, 
       RegNumber = cust.RegNumber 
      }; 

에 등록 된 사람은, 고객이 해당하는 사람이있는 이름이있다; PersonID는 Customer 테이블의 외래 키입니다. 생성 된 SQL을 보면 Person 테이블에서 선택된 모든 열을 볼 수 있습니다. Fyi, DisplayName은 Customer.FirstName 및 LastName을 사용하는 확장 메서드입니다. Person에서 열을 어떻게 제한 할 수 있습니까?

둘째로 Anything 절을 없애고 하위 쿼리를 사용하여 필요한 ProductID가있는 다른 모든 CustomerId를 선택하려고합니다. Exists 절을 생성하기 때문입니다. 아시다시피 LINQ는 접합부 테이블과 관련하여 알려진 문제가 있으므로 Cust.CustomerProducts.Products를 수행 할 수 없습니다. 필수 ProductID가있는 junction 테이블의 모든 고객을 선택하려면 어떻게합니까?

도움/조언을 보내 주시면 감사하겠습니다.

답변

1

:처럼 뭔가

IQueryable<CustomerDisplay> myCustDisplay = 
    from custProd in db.CustomerProducts 
    join regCust in db.RegisteredCustomers 
     on custProd.Customer.ID equals regCust.CustId 
    where 
     custProd.ProductID == reqProdId 
     && regCust.CreditCardNumber != null 
     && regCust.Authorized == true 
    select new CustomerDisplay 
    { 
     Id = cust.Id, 
     Name = cust.Person.Name, 
     RegNumber = cust.RegNumber 
    }; 

이것은 당신의 구문을 단순화하고 잘하면 더 나은 실행 계획에 발생합니다.

그런 다음 Customers와 RegisteredCustomers간에 외래 키 관계를 만드는 것을 고려해야합니다.

Func<MyDataContext, SearchParameters, IQueryable<CustomerDisplay>> 
    GetCustWithProd = 
    System.Data.Linq.CompiledQuery.Compile(
     (MyDataContext db, SearchParameters myParams) => 
     from custProd in db.CustomerProducts 
     where 
      custProd.ProductID == myParams.reqProdId 
      && custProd.Customer.RegisteredCustomer.CreditCardNumber != null 
      && custProd.Customer.RegisteredCustomer.Authorized == true 
     select new CustomerDisplay 
     { 
      Id = cust.Id, 
      Name = cust.Person.Name, 
      RegNumber = cust.RegNumber 
     }; 
    ); 

:

IQueryable<CustomerDisplay> myCustDisplay = 
    from custProd in db.CustomerProducts 
    where 
     custProd.ProductID == reqProdId 
     && custProd.Customer.RegisteredCustomer.CreditCardNumber != null 
     && custProd.Customer.RegisteredCustomer.Authorized == true 
    select new CustomerDisplay 
    { 
     Id = cust.Id, 
     Name = cust.Person.Name, 
     RegNumber = cust.RegNumber 
    }; 

마지막으로, 최적의 속도, LINQ는 컴파일시에 쿼리를 컴파일하기보다는 컴파일 된 쿼리를 사용하여 런타임이이이처럼 보였다 쿼리 초래 당신이 발견 한 것처럼

IQueryable<CustomerDisplay> myCustDisplay = GetCustWithProd(db, myParams); 
+0

thansk Lame Duck, 컴파일 된 LINQ는 생각하지 않았습니다. 그게 좋은 기능 프로그래밍 물건. 또한, 나는 고객과 RegisteredCustomer 사이에 외래 키를 수행하고 (당신이 제안으로) 나는 및 custProd.CreditCardNumber 차이 custProd.Customer.RegisteredCustomer.CreditCardNumber! = null의 사이 가 확실하지 않다! = (I했던 것처럼) LINQ가 custProd를 파악 널 조인의 행이며, SQL이 생성 INNER t1.Id = t2.CustomerID ... ... T2에서 T2로 RegisteredCustomer 가입 .CreditCardNumber IS NOT NULL –

+0

쿼리를 다시 컴파일하십시오. 쿼리는 컴파일 타임이 아니라 런타임에 컴파일됩니다. 컴파일 된 쿼리를 캐시하고 다시 사용할 수 있기 때문에 동일한 쿼리를 여러 번 사용하는 경우에만 도움이됩니다. – Lucas

0

해당 제품에서 검색어를 시작하는 것이 좋습니다 (예 : 첫 번째 단계는 (알렉스 말했듯이) CustomerProducts에서 쿼리를 시작하는 것입니다

from cp in db.CustomerProducts 
join ..... 
where cp.ProductID == reqdProdID 
+0

Alex에게 감사드립니다. LINQ를 뒤집어서 교차점 테이블 항목을 처리했습니다. 누구나 확장 방법 질문에 대한 통찰력을 가지고 있습니까? –

+0

당신의 코드가 Person.FirstName과 Person.LastName에만 접근했다면, 그 코드가 모두 선택되었다고 가정했습니다. 긴 샷 : 확장 메서드없이 시도 했습니까? 예 : Name = cust.Person.FirstName + ""+ cust.Person.LastName –

+0

LINQPad에서 테스트 한 결과 두 필드를 직접 지정하면 DisplayName = cust.FirstName + ""+ cust.LastName, 생성 된 SQL은이 두 필드가 있습니다. –

0

는, 확장 기능 또는 부분 클래스에 정의 된 속성을 사용하는 것이 필요합니다 전체 개체가 처음으로 수화됩니다 : 당신은이 같은 컴파일 된 쿼리를 호출 할 수 있습니다 서버가 이러한 추가 속성에 대해 알지 못하기 때문에 선택 투영이 클라이언트 측에서 수행됩니다. 코드가 전혀 작동하지 않아서 기쁩니다. 쿼리에서 매핑 이외의 다른 값을 사용할 경우 (프로젝션을 제외하고) 런타임 예외가 발생할 수 있습니다. Where 절에서 Customer.Person.DisplayName 속성을 사용하려고하면이 내용을 볼 수 있습니다. 당신이 발견했듯이, 해결 방법은 투영 절의 문자열 연결을 직접 수행하는 것입니다.

Lame Duck, select 절에 사용 된 Cust 변수가 소스 지역 변수 (from 절에)로 선언되지 않았으므로 코드에 버그가 있다고 생각합니다.