0

是的,这是我连续第四天问一个关于摘要的问题,对不起,我会试着去回答一些关于 SQLServer 的问题,以回馈社区。反正...

如何将 Linq 查询的结果投影到抽象基类集合中?这是我的 RecruiterBase 抽象类中的我的方法(还有一个相应的 CandidateBase 抽象类):

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

上述方法会抛出编译时错误,即无法在 Candidate 和 CandidateBase 之间进行隐式转换。

将 db.Candidates 修改为 db.Candidates.Cast() 可以编译所有内容,但我得到一个运行时错误,即在类型 Candidate 和 CandidateBase 之间未定义强制运算符。

我做不到:选择 New CandidateBase { ... } 作为 CandidateBase,因为无法实现抽象。

我也不能在候选人和候选人基础之间创建一个显式转换运算符,因为它再次要求我更新我的摘要

我也不能将我的结果投影到匿名对象中,然后转换为 CandidateBase,因为我在匿名类型和 CandidateBase 类型之间得到相同的运行时强制异常。

这个问题来自昨天的问题, Problem with Covariant return types from an abstract method

Stan R 提供的答案是我让事情变得复杂。我回去,简化了一切(我将实现留在基础中并将其从潜艇中删除)并最终实现了一个有效的 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)
        {            
        }        
    }
4

3 回答 3

1

您可能需要定义 Candidate 和 CandidateBase 使用的 ICandidate 接口,然后您可以返回 IQueryable<ICandidate>。

于 2009-08-27T18:43:06.913 回答
0

贾斯汀,这并不奇怪……这确实是继承的目的。您的 CandidateBase 类为您的 Candidate 类提供了一个基础,因为它是抽象的,这意味着它提供了一些您以后不必担心的逻辑。我认为最好用一个例子来解释。

假设您有 2 个不同的候选类,它们都想提供一些功能,比如说 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();
}

现在假设 CandidateA 从特定的 Web 服务获取他的简历

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

}

现在假设您有 CandidateB,并且您将他的简历存储在磁盘上的某个位置。

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

}

在某些时候,当您调用 GetCandidates() 您的代码时,您不必担心您的候选人是哪种类型,您仍然可以通过在 CandidateBase 上调用 GetResume() 来获取他们的简历。

顺便说一句,贾斯汀,如果它真的困扰你,你可以在调用 GetCandidates()

IQueryable<CandidateA> candidates = recruiterClass.GetCandidates().Cast<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
                    }
                    )

        }
    }

你可以这样使用

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

我认为这是一个比所有这些 Casts 更清洁的解决方案 :)

于 2009-08-27T18:56:13.343 回答
0

我有点困惑......似乎对原始问题进行了一些编辑,但这些编辑的时间/地点尚不清楚。无论如何,除非我误解了某些东西,否则您的 DataContext 中的 Candidate 实体应该派生自 CandidateBase。但是,根据您收到的错误以及您对该错误的解决方案,它似乎没有这样做。

我会更新您的映射以使您的 Candidate 类派生自 CandidateBase 类。一旦您的 DataContext 返回的实际 Candidate 实体正确地派生自 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;
}
于 2009-08-27T19:03:10.257 回答