2013-03-09 1 views
1

WCF 데이터 서비스를 사용하여 다음 LINQ 쿼리를보다 잘 디자인하는 방법에 대한 조언을 구합니다. 요구 사항은 ComboBox를 통해 Employees 목록을 표시하는 것입니다. 다음과 같이LINQ 문 최적화 - 더 나은 디자인을위한 조언을 구하십시오.

DB를 테이블 구조는 다음과 같습니다

직원은 많은 프로젝트에 할당 할 수 있고 프로젝트는 많은 직원을 가질 수있다. 이 관계는 3 테이블을 통해 설계되었습니다 : [Employees] 1--* [EmployeeProjects] *--1 [Projects]. 도트 국가에서는 객체 트리를 가로 지르는 경우와 비슷할 것입니다 : Employee.EmployeeProjects.Project.

다음 LINQ 문은 EmployeeProjects의 목록을 반환하지만 내가 선택한 것은 특정 프로젝트의 일부인 Employee 목록입니다. 이상적으로는 IQueryable<Employee>을 실행하는 것이 맞지만 EmployeeProjects 링크 (다수)로 인해 LINQ 문을 구성하는 방법을 모르겠습니다. 내 딜레마가 보이니?

아래 LINQ 문에서 볼 수 있듯이 직원 및 프로젝트 측면이 모두 1 개의 관계이므로 "많은"측면을 다루지 않기 때문에 IQueryable<EmployeeProject>을 수행합니다. EmployeeProjects의 목록을 얻은 후에 나는 또 다른 .Select() 문을 실행하여 내가 궁극적으로 취한 조치 즉 고유 한 직원 이름 목록을 반환합니다. .Select(results => results.Employee.Name).Distinct().

private IQueryable<EmployeeProject> GetEmployeeProjects() 
{ 
    var employeeProjects = service 
     .CustomQuery<EmployeeProject>() 
     .Where(et => ep.Project.Name == "TrackerX 43" || 
        ep.Project.Name == "AccountingX 11" || 
        ep.Project.Name == "TopX 2" || 
        ep.Project.Name == "SiteX 32" || 
        ep.Project.Name == "BuildingX 3" || 
        ep.Project.Name == "ReportX 321" || 
        ep.Project.Name == "PrototypeX 78" || 
        ep.Project.Name == ... more ...) 
     .OrderBy(ep => ep.Employee.Name) 
     .Select(ep => new EmployeeProject 
     { 
      Id = ep.Id 
      Project = new Project 
      { 
       Name = ep.Project.Name 
      }, 
      Employee = new Employee 
      { 
       Id = ep.Employee.Id, 
       Name = ep.Employeet.Name 
      } 
     }); 

    return employeeProjects; 
} 

더 나은 디자인에 대한 조언을 주시면 감사하겠습니다.

답변

2

EmployeeProject을 새로 만들거나 기존의 것을 반품 할 수 있습니까?

//Move inside the method call if you need it to be dynamic. 
private readonly string[] compareProjectNames = new[] 
{ 
    "AccountingX 11", "TopX 2", "SiteX 32", 
    "BuildingX 3", "ReportX 321", "PrototypeX 78" 
}; 
private IQueryable<EmployeeProject> GetEmployeeProjects() 
{ 
    var employeeProjects = service.CustomQuery<EmployeeProject>() 
     .Where(et => compareProjectNames.Contains(ep.Project.Name)) 
     .OrderBy(ep => ep.Employee.Name) 
     .Select(ep => new EmployeeProject 
     { 
      Id = ep.Id, 
      Project = new Project 
      { 
       Name = ep.Project.Name 
      }, 
      Employee = new Employee 
      { 
       Id = ep.Employee.Id, 
       Name = ep.Employee.Name 
      } 
     }); 
    return employeeProjects; 
} 

편집 :

좀 더 신중하게 게시물을 읽고 나면, 당신은 또한 수 있습니다 당신이 할 수

한 가지는 배열로 문자열을 결합하고,이처럼 비교입니다 별개의 프로젝트 이름을 찾기 위해 이와 같은 것을 찾으십시오.

List<EmployeeProject> employeeProjects = new List<EmployeeProject>(); 
employeeProjects 
    .GroupBy(et => et.Project.Name) 
    .Select(grp => grp.First()); 

또는 1 문

List<EmployeeProject> employeeProjects = new List<EmployeeProject>(); 
employeeProjects 
     .Where(et => compareProjectNames.Contains(et.Project.Name)) 
     .GroupBy(cust => cust.Project.Name) //groups them by name, so no need to order 
     .Select(grp => grp.First()) //selects the first distinct name per group 
     .Select(ep => new EmployeeProject 
     { 
      Id = ep.Id, 
      Project = new Project 
      { 
       Name = ep.Project.Name 
      }, 
      Employee = new Employee 
      { 
       Id = ep.Employee.Id, 
       Name = ep.Employee.Name 
      } 
     }); 
+0

필자는 논리가 의도적으로 거꾸로되어있어 제약 조건 목록을 사용하고 필드를 비교 (또는 포함)한다는 점을 강조해야한다고 생각합니다. 일반적인 방법 (field.Contains (constraint_array))을 수행 할 수는 있지만 뒤로 방향을 사용하면보다 간결한 SQL 쿼리를 생성 할 수 있습니다. – Tory

+0

오타이기 때문에 Compares -> Contains를 수정했습니다. 그러나 나는 당신이 다른 방향으로 무엇을 의미하는지 확신 할 수 없다. 'str.Contains (arrayOfStr)'는 유효한 구문이 아닙니다. – Corylulu

+0

예, 죄송합니다. 그게 내가 직접 시도하는 것보다 뭔가를 확인하는 것입니다. 나는 잘못 읽었고 다른 방법으로도 허용 할 수는 있지만 (실제로 읽은 것은 다른 LINQ를 다른 SQL 쿼리로 호출하는 것입니다) 제가 말한 다른 모든 것은 여전히 ​​유효합니다. – Tory

0

EF를 서버 측에서 사용하는 경우 클라이언트에서 EmployeeProject 테이블을 완전히 숨길 수 있어야합니다. EF는 DB 구조를 두 개 이상의 엔티티 집합 (Employees 및 Projects)과 Many-Many 관계 (두 개의 1-Many 한 방향 관계를 생성하는 세부 사항)로 변환 할 수 있어야합니다.

클라이언트에서 볼 때 Employees 엔터티 집합처럼 보입니다. 각 인스턴스에는 직원이 참여하는 프로젝트 목록 인 Projects 속성이 있습니다. 마찬가지로 엔터티 집합 프로젝트 각 인스턴스의 속성이 Employees 인 프로젝트 해당 프로젝트에 할당 된 직원 목록.

~/프로젝트 :

그런 다음 위의 쿼리가 훨씬 더 간단 할 수있다 (곤란에 대한 URL 표기법을 사용하여 LINQ 버전 일종의 분명하다, 또한 프로젝트 이름의 목록을 간소화)?$ filter = (Name eq 'TopX 2') 또는 (Name eq 'SiteX 32') & $ expand = Employess

이렇게하면 지정된 이름을 가진 모든 프로젝트를 가져올 수 있으며 각 프로젝트마다 할당 된 모든 직원을 얻을 수 있습니다.

중간 테이블은 연결에 대한 몇 가지 추가 정보를 저장하면 나머지 두 테이블을 조인 할 수 있다고 가정합니다. 그러면 작동하지 않습니다.

+0

Hello Vitek, 답장을 보내 주셔서 감사합니다.하지만 EmployeeProject 클래스/테이블은 포함되어야하고 다른 세부 정보를 제공해야하는 추가 속성이 필요하므로 필요합니다. 이게 도움이 되나요? 감사합니다 ... – user118190

+0

다음 내 대답에 언급 된대로, 그 접근법을 사용할 수 없습니다. 당신이 가지고있는 것은 이미 유일한 실행 가능한 접근법처럼 보입니다. –

+0

답변을 주신 Vitek에게 감사드립니다. 내가 Employee 컬렉션을 반환하기를 원하지만 확인할 방법이 없으므로 먼저 EmployeeProjects 컬렉션을 반환해야합니다. 그것은 단지 옳은 것처럼 보이지 않습니다. 그것이 전부입니다. .SelectMany()를 사용하는 것과 같은 대안을 찾으려고했지만 내 진술에 그것을 어떻게 마사지 할 지 확신하지 못했습니다. – user118190