Как спроецировать результаты Linq в абстрактный конструктор? - PullRequest
0 голосов
/ 27 августа 2009

Да, это мой четвертый день подряд, чтобы задать вопрос об аннотациях, извините, я постараюсь ответить на несколько вопросов о SQLServer, чтобы вернуть пользу сообществу. Во всяком случае ...

Как я могу проецировать результаты запроса Linq в абстрактную коллекцию базовых классов? Вот мой метод my из моего абстрактного класса 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.

Эта проблема возникла из вчерашнего вопроса, Проблема с ковариантными типами возврата из абстрактного метода

Ответ, предоставленный Стэном Р., заключался в том, что я все усложнял. Я вернулся, все упростил (оставил имплментацию в базе и удалил ее из сабвуферов) и в итоге получил работающий метод 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)
        {            
        }        
    }

Ответы [ 3 ]

1 голос
/ 27 августа 2009

Вам может потребоваться определить интерфейс ICandidate, который используют Candidate и CandidateBase, тогда вы можете вместо этого вернуть IQueryable .

0 голосов
/ 27 августа 2009

Я немного сбит с толку ... казалось, что есть некоторые правки в первоначальном вопросе, но когда / где эти правки были сделаны, не ясно. В любом случае, если я что-то не так понимаю, сущность Candidate из вашего DataContext должна быть производной от CandidateBase. Однако, на основании полученной вами ошибки и вашего решения этой ошибки, похоже, это не происходит.

Я бы обновил ваше отображение, чтобы сделать ваш класс Candidate производным от класса CandidateBase. Как только фактическая сущность Candidate, которую возвращает ваш 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 голосов
/ 27 августа 2009

Джастин, это не странно ... это действительно то, для чего предназначено наследование. Ваш класс 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 получает свое резюме от определенной веб-службы

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 (), вам не нужно беспокоиться о том, какого типа ваш кандидат, вы все равно можете получить его резюме, вызвав GetResume () в CandidateBase.

кстати, Джастин, если это действительно беспокоит вас, вы всегда можете вернуться к CandidateA после вызова 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>();

Я думаю, что это гораздо более чистое решение, чем все эти броски:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...