2009-08-27 5 views
0

예, 초록에 관한 질문을하는 것이 4 일째되는 날입니다. 죄송합니다. SQLServer에 대한 몇 가지 질문에 답변을 드리겠습니다. 어쨌든 ...Linq 결과를 추상 생성자로 어떻게 투영합니까?

Linq 쿼리의 결과를 추상 기본 클래스 컬렉션에 어떻게 투영 할 수 있습니까? 여기 내 RecruiterBase 추상 클래스에서 내 내 방법 (해당 CandidateBase 추상 클래스도 있습니다)입니다 :

public IQueryable<CandidateBase> GetCandidates() 
{ 
    return from candidates in db.Candidates 
     where candidates.RecruiterId == this.RecruiterId 
     select candidates; 
} 

위의 방법은 암시 적 변환이 후보와 CandidateBase 사이 수 없다는 컴파일시 오류가 발생합니다.

db.Candidates.Cast()에 db.Candidates를 수정하면 모든 사항을 컴파일 할 수 있지만 런타임 오류가 발생합니다. 즉, 유형이 Candidate와 CandidateBase 사이에 정의되지 않습니다.

할 수 없습니다. 추상을 구현할 수 없으므로 CandidateBase로 새 CandidateBase {...}를 선택하십시오. 다시 내 추상적까지 새에 저를 필요로하기 때문에

은 아니다 내가 후보와 후보베이스 사이의 명시 적 변환 연산자를 만들 수 있습니다

도 아니다 나는 익명의 객체로 내 결과를 투영 내가 먹을수록 다음 CandidateBase으로 캐스팅 할 수 있습니다 익명의 형태와 CandidateBase의 형태와 같은 실행시 강제 변환 예외.

이 문제는 스탠 R에서 제공하는 대답은 내가 복잡한 물건을 만드는 것을이었다 Problem with Covariant return types from an abstract method

, 어제의 질문에서 약왔다. 난 다시 가서 간단하게 모든 것을 (I베이스에 implmentation을 떠나 잠수정에서 제거) 및 작업 GetCanidates의 같은 구현 방법 결국 :

public IQueryable<CandidateBase> GetCandidates() 
{ 
    return (from candidates in db.Candidates 
     where candidates.RecruiterId == this.RecruiterId 
     select new CandidateA 
     { 
      CandidateId = candidates.CandidateId, 
      LastName = candidates.LastName, 
      RecruiterId = candidates.RecruiterId 
     }).Cast<CandidateBase>(); 
} 

위의 방법은 컴파일 작품, 나는 ' 입안에서 선물용 말을 보려고하지 않고, 이제는 기본 유형의 하위 유형에 대한 참조 (CandidateA에 결과를 투영 할 때)가 있으며 이상하게 보입니다. 기본 유형 내에서 하위 유형에 대한 참조가 괜찮 으면 내 질문에 자유롭게 투표하십시오.

감사합니다.

전체 클래스 인증 된 정의 :

public abstract class RecruiterBase 
    { 
     public int RecruiterId { get; set; } 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 

     public RecruiterBase() 
     { 
     } 

     public RecruiterBase(int id) 
     { 
      DataClasses1DataContext db = new DataClasses1DataContext(); 
      Recruiter rc = db.Recruiters.SingleOrDefault(r => r.RecruiterId == id); 

      this.RecruiterId = rc.RecruiterId; 
      this.FirstName = rc.FirstName; 
      this.LastName = rc.LastName; 
     } 

     public IQueryable<CandidateBase> GetCandidates() 
     { 
      DataClasses1DataContext db = new DataClasses1DataContext(); 
      return (from candidates in db.Candidates 
        where candidates.RecruiterId == this.RecruiterId 
        select new CandidateA 
        { 
         CandidateId = candidates.CandidateId, 
         LastName = candidates.LastName, 
         FirstName = candidates.FirstName, 
         RecruiterId = candidates.RecruiterId 
        } 
        ).Cast<CandidateBase>(); 
     } 
    } 



public abstract class TempCandidateBase 
    { 
     public int CandidateId { get; set; } 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 
     public int? RecruiterId { get; set; } 

     public CandidateBase() 
     { 
     } 

     public CandidateBase(int id) 
     { 
      DataClasses1DataContext db = new DataClasses1DataContext(); 

      Candidate candidate = db.Candidates.SingleOrDefault(c => c.CandidateId == id); 

      this.CandidateId = candidate.CandidateId; 
      this.FirstName = candidate.FirstName; 
      this.LastName = candidate.LastName; 
      this.RecruiterId = candidate.RecruiterId; 
     } 
    } 

public class RecruiterA : RecruiterBase 
    { 
     public RecruiterA() 
      : base() 
     { 
     } 

     public RecruiterA(int id) 
      : base(id) 
     {    
     } 
    } 


public class CandidateA : CandidateBase 
    { 
     public CandidateA() 
      : base() 
     { 
     } 

     public CandidateA(int id) 
      : base(id) 
     {    
     }   
    } 
+0

당신이 우리에게 후보자 및 CandidateBase 클래스뿐만 아니라 실제 관련 컴파일러 에러 메시지를 표시 할 수? –

+0

정확한 게시판을 사용하여 잠시 편집 한 게시물을 보내 드리겠습니다. –

답변

1

당신은 후보와 CandidateBase 사용이, 당신은 대신에 IQueryable < ICandidate>를 반환 할 수있는 ICandidate 인터페이스를 정의해야 할 수도 있습니다.

0

저스틴, 그것은 이상하지 않습니다. 그것은 실제로 상속을위한 것입니다. CandidateBase 클래스는 후보 클래스의 기초를 제공하며 추상이기 때문에 나중에 신경 쓸 필요가없는 논리를 제공합니다. 나는 그것이 예를 들어 설명하는 것이 더 낫다고 생각한다.

두 개의 후보 클래스가 있고 둘 다 일부 기능을 제공하고 싶다면 GetResume()이라고 말하면서 다음과 같이 추상 클래스 나 인터페이스를 만들 수 있습니다.귀하의 경우에 당신은

public class CandidateBase 
{ 
    //some logic that you might need to share between Candidates 
    //such as storing Name, Age..etc 

    // your abstract method 
    public abstract String GetResume(); 
} 
같은 추상 클래스를 만든 지금

public class CandidateA : CandidateBase 
{ 
    public String GetResume() 
    { 
     //some logic to get Resume from some web service 
     return resumeStr; 
    } 

} 

이제 CandidateB이 있다고 할 수 있습니다 당신은 디스크 어딘가에 자신의 이력서를 저장 CandidateA 특정 웹 서비스에서 자신의 이력서를 얻을 말할 수

. 당신이 GetCandidates 전화를 어떤 점에서

public class CandidateB : CandidateBase 
{ 
    public String GetResume() 
    { 
     //some logic to get Resume from disk 
     return resumeStr; 
    } 

} 

코드를() 당신이 어떤에 대한 귀하의 후보가 입력 걱정할 필요가 없습니다, 당신은 여전히 ​​CandidateBase에 GetResume()를 호출하여 자신의 이력서를 얻을 수 있습니다.

정말 당신을 귀찮게하는 경우 BTW 저스틴, 당신은 항상 당신은 내가이 문제를 해결해야한다고 생각

저스틴를 추가하려면 GetCandidates()

IQueryable<CandidateA> candidates = recruiterClass.GetCandidates().Cast<CandidateA>(); 

EDIT를 호출 한 후 CandidateA 다시 캐스트 할 수 있습니다 나에게 알려줘.

public abstract class CandidateBase 
    { 
     public int CandidateId { get; set; } 
     public string LastName { get; set;} 
     public string FirstName { get; set;} 
     public string RecruiterId { get; set; } 

     //the rest of your logic 
    } 

public class RecruiterBase 
    { 
     // Constructors declared here 

     // ----HERE IS WHERE I AM BREAKING DOWN---- 
     public IQueryable<T> GetCandidates<T>() where T:CandidateBase, new() 
     { 

      DataClasses1DataContext db = new DataClasses1DataContext(); 
      return (from candidates in db.Candidates 
        where candidates.RecruiterId == this.RecruiterId 
        select new T() 
        { 
         CandidateId = candidates.CandidateId, 
         LastName = candidates.LastName, 
         FirstName = candidates.FirstName, 
         RecruiterId = candidates.RecruiterId 
        } 
        ) 

     } 
    } 

당신은 내가이 모든 캐스트보다 훨씬 청소기 솔루션 :

+0

저는 여러분에게 Stan을 따르고 있다고 생각합니다.하지만베이스에 GetResume을 구현하는 것이 그리 중요하지 않습니다. CandidateBase의 GetCandidates()에있는 CandidateA에 대한 참조로 이제는 기본 클래스가 내 구현에 대한 지식을 가지고 있어야한다는 사실이 더 중요합니다. 사실 CandidateA를 구현하지 않고서도 GetCandidate()를 사용하여 추상 클래스를 컴파일 할 수 없었을 것입니다. 그것이 던지는 것입니다. 내가 말했듯이, 나는 너의 도움을 두들겨주지 않고있다. 나는 단지 내 자신의 무지를 지나치려고 노력하고있다. –

+0

저스틴, 기지에는 구현이 없습니다. 그것의 추상을 주목하라. 즉, 기본을 상속받은 모든 클래스는 추상 메소드를 구현해야한다고 말한다. 추상적 인 것을 만들 때 그것을 구현하기 위해 상속받은 다른 클래스가 필요합니다. 기본 클래스는 CandidateA 또는 CandidateB의 구현이 무엇인지 알지 못하므로 걱정하지 않아도됩니다. –

+0

아, 저스틴. 마침내 당신의 문제를보기 시작했습니다. Recruiter 클래스에 특정 후보자를 만들고 싶지는 않습니까? 예를 들어 신입 사원 클래스에 특별히 CandidateA를 작성하고 싶지는 않습니다. –

0

나는 조금 혼란 스러워요 ... 거기 듯 생각이

IQueryable<CandidateA> candidates = recruiterClass.GetCandidates<CandidateA>(); 

처럼 이것을 사용할 수 있습니다 원래 질문에 대해 약간의 수정을 가졌지 만 편집이 언제 어디서 이루어 졌는지는 분명하지 않습니다. 어쨌든, 내가 오해하지 않는 한, DataContext의 Candidate 엔티티는 CandidateBase에서 파생되어야합니다. 그러나받은 오류와 해당 오류에 대한 해결책에 따라 오류가 발생하지 않는 것으로 보입니다.

Candidate 클래스를 CandidateBase 클래스에서 파생시키기 위해 매핑을 업데이트합니다. 당신의 DataContext가 제대로 반환 실제 후보 엔티티가 CandidateBase 클래스에서 파생되면, 그 다음이 가능해야한다 :

public IQueryable<CandidateBase> GetCandidates() 
{ 
    var candidates = from candidates in db.Candidates 
        where candidates.RecruiterId == this.RecruiterId 
        select candidates; 

    var based = candidates.Cast<CandidateBase>(); 
    return based; 
} 
+0

위의 코드는 (Linq genned) Candidates 클래스와 CandidateBase 클래스에서 오는 "강제 연산 자 정의되지 않음"예외를 발생시킵니다. –

+0

CandidateBase 클래스에서 후보를 파생하려면 수동 매핑을 수행해야합니다. 비주얼 디자이너는 매번 코드를 다시 생성하여 수정할 수 있습니다. POCO 접근법을 사용하여 직접 클래스를 작성한 다음 매핑 파일을 수동으로 생성하거나 작성하면 유연성이 훨씬 향상됩니다. 위의 코드는 다음 클래스를 얻을 수있는 경우 가능합니다. public class Candidate : CandidateBase {...} – jrista

관련 문제