2012-06-29 2 views
2

커미션 추적 시스템에서 작업 중입니다. 비즈니스 사례는 영업 직원과 고객간에 다 대다 관계가 필요합니다. (간체) 엔티티는 다음과 같습니다 순간Entity Framework 다 대다 쿼리가 잘못 생성 됨 SQL

public class Customer { 
    public int Id { get; set; } 
    public string Name { get; set; } 

    public virtual ICollection<CustomerSeller> CustomerSellers { get; set; } 
    public virtual ICollection<Payment> Payments { get; set; } 
} 

public class Seller { 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual ICollection<CustomerSeller> CustomerSellers { get; set; } 
} 

// join table w/payload for many-to-many relationship 
public class CustomerSeller { 
    public int Id { get; set; } 
    public Seller Seller { get; set; } 
    public Customer Customer { get; set; } 
    public decimal CommissionRate { get; set; } 
} 

public class Payment { 
    public int Id { get; set; } 
    public Customer ReceivedFrom { get; set; } 
    public DateTime Date { get; set; } 
    public decimal Amount { get; set; } 
} 

내 목표는 주어진 판매 사람에게 연결되어 고객에게 모든 지불의 목록을 얻을 수 있습니다. 이 코드 내 ASP NET MVC 사이트에

select Payment.* 
from Payment 
inner join CustomerSeller on CustomerSeller.Customer_Id = Payment.ReceivedFrom_Id 
where CustomerSeller.Seller_Id = @sellerIdToQuery 

내가 LINQ/EF와 함께이 노력하고있어 : 내가 바로 SQL을 작성하는 경우는 다음과 같이 보일 것이다

public ActionResult Sales(int id) { 
    var qry = (
    from p in db.Payments 
    join cs in db.CustomerSellers on p.ReceivedFrom equals cs.Customer 
    where cs.Seller.Id == id 
    select p); 
    var paymentList = qry.ToList(); 
    return View(paymentList); 
} 

이 작업을 수행, 하지만 무대 뒤의 SQL은 (는 분석 내 SQL-디코딩 능력을 넘어) waaay 복잡 같습니다

{SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[Date] AS [Date], 
[Extent1].[Amount] AS [Amount], 
[Extent1].[ReceivedFrom_Id] AS [ReceivedFrom_Id] 
FROM [dbo].[Payment] AS [Extent1] 
INNER JOIN [dbo].[CustomerSeller] AS [Extent2] ON EXISTS (SELECT 
    1 AS [C1] 
    FROM  (SELECT 1 AS X) AS [SingleRowTable1] 
    LEFT OUTER JOIN (SELECT 
     [Extent3].[Id] AS [Id] 
     FROM [dbo].[Customer] AS [Extent3] 
     WHERE [Extent1].[ReceivedFrom_Id] = [Extent3].[Id]) AS [Project1] ON 1 = 1 
    LEFT OUTER JOIN (SELECT 
     [Extent4].[Id] AS [Id] 
     FROM [dbo].[Customer] AS [Extent4] 
     WHERE [Extent2].[Customer_Id] = [Extent4].[Id]) AS [Project2] ON 1 = 1 
    LEFT OUTER JOIN (SELECT 
     [Extent5].[Id] AS [Id] 
     FROM [dbo].[Customer] AS [Extent5] 
     WHERE [Extent1].[ReceivedFrom_Id] = [Extent5].[Id]) AS [Project3] ON 1 = 1 
    LEFT OUTER JOIN (SELECT 
     [Extent6].[Id] AS [Id] 
     FROM [dbo].[Customer] AS [Extent6] 
     WHERE [Extent2].[Customer_Id] = [Extent6].[Id]) AS [Project4] ON 1 = 1 
    WHERE ([Project1].[Id] = [Project2].[Id]) OR (([Project3].[Id] IS NULL) AND ([Project4].[Id] IS NULL)) 
) 
WHERE [Extent2].[Seller_Id] = @p__linq__0} 

내 LINQ 쿼리가 (나는 새로운 해요) 심하게 형성되어있는 경우에 특히 관심이 있어요 .. 어떻게 작성해야합니까? 아니면 내 조직의 구조에 문제가 있습니까? 또는 SQL을 사용하면 프로덕션 환경에서 많은 양의 데이터를 효율적으로 실행할 수 있습니까?

는 PROGRESS :

첫째, Slauma 두 개의 새로운 쿼리를 제안했다. 그들과 함께 실험하면서 SQL은 Customer 테이블과 Seller 필드에 대한 Join 테이블 CustomerSeller에 NULL을 처리하는 데 추가적인 노력을 기울이고 있음을 알았습니다. 이 필드는 null이 허용되지 않아야하므로 내 부분에서 오류가 발생했습니다.

public class CustomerSeller { 
    public int Id { get; set; } 
    [Required] 
    public Seller Seller { get; set; } 
    [Required] 
    public Customer Customer { get; set; } 
    public decimal CommissionRate { get; set; } 
} 

Slauma가 쓴 첫 번째 질의 : 나는 엔티티의 [필수]로 설정 Slauma 권장

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[Date] AS [Date], 
[Extent1].[Amount] AS [Amount], 
[Extent1].[ReceivedFrom_Id] AS [ReceivedFrom_Id] 
FROM [dbo].[Payment] AS [Extent1] 
WHERE EXISTS (SELECT 
    1 AS [C1] 
    FROM [dbo].[CustomerSeller] AS [Extent2] 
    WHERE ([Extent1].[ReceivedFrom_Id] = [Extent2].[Customer_Id]) AND ([Extent2].[Seller_Id] = @p__linq__0) 
) 

다음 팅겨했다 :

var qry = from p in db.Payments 
      where p.ReceivedFrom.CustomerSellers.Any(cs => cs.Seller.Id == id) 
      select p; 

가 생성 훨씬 뛰어난 SQL을 가지고 전체 엔터티가 아닌 Id 필드에서 원래 쿼리에 참여하십시오.

var qry = from p in db.Payments 
      //old: join cs in db.CustomerSellers on p.ReceivedFrom equals cs.Customer 
      //new: 
       join cs in db.CustomerSellers on p.ReceivedFrom.Id equals cs.Customer.Id 
      where cs.Seller.Id == id 
      select p; 
내가 SQL에 직접 자신을 쓴 것입니다 무슨 본질적으로

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[Date] AS [Date], 
[Extent1].[Amount] AS [Amount], 
[Extent1].[ReceivedFrom_Id] AS [ReceivedFrom_Id] 
FROM [dbo].[Payment] AS [Extent1] 
INNER JOIN [dbo].[CustomerSeller] AS [Extent2] ON [Extent1].[ReceivedFrom_Id] = [Extent2].[Customer_Id] 
WHERE [Extent2].[Seller_Id] = @p__linq__0 

:

이 매우 높은 품질의 SQL 문을 생성합니다.

테이크 아웃 :

(1) 키를 오히려 전체 개체보다 가입.

(2) 조인 테이블이 다 대다 매핑 필드에 대해 null을 가질 수 없으면 [필수]로 표시하여 쿼리를 약간 단순화합니다.

(3) 특히 빈번하게 사용되거나 많은 양의 데이터를 만질 수있는 경우 linq 쿼리를 위해 비하인드 SQL을 확인하십시오. 괴물이 숨어있을 수 있습니다.

(4) 슬라 우마는 신사이자 학자입니다.:-)

내가 쿼리 이런 식으로 작성합니다
+0

솔직히 말해서 그것은 혼란스러워 보입니다. 쿼리 계획과 쓴 쿼리를 보았습니까? 이 밝혀 – Charleh

답변

1

: 확장 방법과

var qry = from p in db.Payments 
      where p.ReceivedFrom.CustomerSellers.Any(cs => cs.Seller.Id == id) 
      select p; 
var paymentList = qry.ToList(); 

또는 완전히 :

var qry = db.Payments 
    .Where(p => p.ReceivedFrom.CustomerSellers.Any(cs => cs.Seller.Id == id)); 
var paymentList = qry.ToList(); 

는 SQL이 다를 수 것인지 또는 얼마나 많은 모르겠어요를 당신의 질문.

편집

대안 :

var qry = db.CustomerSellers 
    .Where(cs => cs.Seller.Id == id) 
    .SelectMany(cs => cs.Customer.Payments); 
var paymentList = qry.ToList(); 

Seller 경우 CustomerSellers에서 Customer이 결과 Payment의 더 중복이 없어야 복합 고유 제한 조건이있다. 그렇지 않으면 SelectMany 뒤에 Distinct()을 추가해야합니다.

+0

는 더욱 향상된 :... 가 '{ [Extent1]에서 [ID], [Extent1] 일] AS [일자] AS [ID] [Extent1 [양] AS [양 WHERE EXISTS [Extent1 바와 같이, 는 [Extent1]. ReceivedFrom_Id] AS [ReceivedFrom_Id] [DBO] FROM. 납부 ([DBO] FROM \t] \t 1 AS [C1을 선택. CustomerSeller] AS [Extent2]. [Seller_Id] = @ p__linq__0) \t WHERE ([Extent2]. [Customer_Id] IS NOT NULL)와 ([Extent1]. [ReceivedFrom_Id] = [Extent2]. [Customer_Id]) )}' –

+0

@LarryS : BTW, 이상하게 보이는 부분 내가 당신의 LINQ 쿼리에서'p.ReceivedFrom.Id equals cs.Customer.Id' 키 대신에'p.ReceivedFrom equals cs.Customer' 엔티티 전체를 합칩니다. 어쩌면이 변경조차도 귀하의 질의를 향상시킬 것입니다 ... – Slauma

+0

@LarryS : 또 다른 대안은 제 편집을보십시오. – Slauma

관련 문제