Вернуть разные объекты одним оператором LINQtoSQL - PullRequest
3 голосов
/ 23 февраля 2010

Вот моя проблема: у меня есть IPerson, который реализуется Сотрудником и Студентом. То, что я действительно хочу, это то, что вы видите ниже. Один оператор LINQ для получения каждого типа IPerson. Это прекрасно работает, пока я не вызову метод;). Имеет смысл объяснить, почему я получаю ошибку, но я действительно изо всех сил пытаюсь найти достойный способ извлечь все объекты IPerson из БД и избежать размещения операторов switch во всем моем приложении.

public IQueryable<IPerson> getPersons() {

        // gives Types in Union or Concat have different members assigned error

        var people = from p in db.Persons select p;

        var students = (from s in people
                        where s.TypeId == (int)PersonType.Student
                        select new Student
                        {
                            Id = s.Id,
                            Age = s.Age.GetValueOrDefault(0),
                            Name = s.Name,
                            Major = s.Student.Major ?? "None",
                            CreditHours = s.Student.CreditHours.GetValueOrDefault(0),
                            PersonType = (PersonType)s.TypeId
                        }).Cast<IPerson>();
        var employees = (from e in people
                        where e.TypeId == (int)PersonType.Employee
                        select new Employee
                        {
                            Id = e.Id,
                            Age = e.Age.GetValueOrDefault(0),
                            Name = e.Name,
                            PersonType = (PersonType)e.TypeId,
                            Salary = e.Employee.Salary.GetValueOrDefault(0)
                        }).Cast<IPerson>();

        return students.Concat<IPerson>(employees);
        //return (students.ToList()).Concat<IPerson>(employees.Cast<IPerson>().ToList()).AsQueryable<IPerson>();
    }

Выше приведен закомментированный оператор возврата, который по существу выполняет .ToList () и отказывается от всего процесса отложенного выполнения, создавая два оператора SQL - не идеально.

Любая помощь приветствуется!

Ответы [ 2 ]

2 голосов
/ 23 февраля 2010

Как насчет этого:

public IQueryable<IPerson> getPersons() {

    // gives Types in Union or Concat have different members assigned error

    var people = from p in db.Persons select p;

    return (from s in people
                    where s.TypeId == (int)PersonType.Student
                    select new Student
                    {
                        Id = s.Id,
                        Age = s.Age.GetValueOrDefault(0),
                        Name = s.Name,
                        Major = s.Student.Major ?? "None",
                        CreditHours = s.Student.CreditHours.GetValueOrDefault(0),
                        PersonType = (PersonType)s.TypeId
                    }).Cast<IPerson>().Union((from e in people
                        where e.TypeId == (int)PersonType.Employee
                        select new Employee
                        {
                            Id = e.Id,
                            Age = e.Age.GetValueOrDefault(0),
                            Name = e.Name,
                            PersonType = (PersonType)e.TypeId,
                            Salary = e.Employee.Salary.GetValueOrDefault(0)
                        }).Cast<IPerson>());
}

Не намного лучше, но вы получаете это за один звонок. Или, что я бы сделал, это что-то вроде этого:

public IPerson GetPerson(Person p) //I'm guessing that the objects in collection db.Persons is of type Person
{
    IPerson ret;
    switch(p.TypeId)
    {
        case (int)PersonType.Student: ret = .......break;
        case (int)PersonType.Employee: ret = ......break;
    }
    return ret;
}

public IQueryable<IPerson> getPersons() {
    return (from p in db.Persons select p).ToList().Select(p => GetPerson(p)).AsQueryable();
}

Но, опять же, вы получаете заявление о переключении. Кроме того, если вам не нравится делать ToList () на БД (если я правильно помню, LinqToSQL не поддерживает функции, использующие конструкторы с переменными), вы можете попробовать добавить метод GetPerson (хотя я, вероятно, переименую его) в класс Person, сгенерированный LinqToSQL (частичный класс), но я не уверен, что это допустимо.

Но как вы собираетесь использовать IQueryable, полученный от getPersons, без использования switch, я не знаю.

0 голосов
/ 26 февраля 2010

Вот что я в итоге сделал:

Репозиторий

public IQueryable<Database.Person> getDbPersons() {
    return from p in db.Persons select p;
}

// Called by Service layer when viewing all People
public IQueryable<Person> getPersons() {
    return from p in getDbPersons() select new Person { //yada yada };
}

Сервисный уровень

public IList<Person> getPersons() {
    return from p in repository.getPersons() return p;
}

public IPerson getPerson(int id) {
    return repository.getDbPersons().withPersonId(id);
}

// Person Filter Class
public static class PersonFilters
{
    public static IPerson WithPersonId(this IQueryable<SqlServer.Person> qry, int Id)
    {
        return (from p in qry
                where p.Id == Id
                select p).Select(p => ThisPerson(p)).SingleOrDefault();
    }

    private static IPerson ThisPerson(OneToOne.Data.SqlServer.Person x)
    {
        IPerson ret;
        switch (x.TypeId)
        {
            case (int)PersonType.Employee:
                var e = new Employee();
                e.Id = x.Id;
                e.Name = x.Name;
                e.Age = x.Age.GetValueOrDefault(0);
                e.Salary = x.Employee.Salary.GetValueOrDefault(0);
                e.PersonType = PersonType.Employee;
                ret = e;
                break;
            case (int)PersonType.Student:
                var s = new Student();
                s.Id = x.Id;
                s.Name = x.Name;
                s.Age = x.Age.GetValueOrDefault(0);
                s.Major = x.Student.Major;
                s.PersonType = PersonType.Employee;
                ret = s;
                break;
            default:
                throw new Exception("Bad Person Type");
        }
        return ret;
    }
}

Еще раз спасибо, Alxandr, за то, что указал мне правильное направление!

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