Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return different objects with one LINQtoSQL statement

I have an IPerson which is implemented by Employee and Student. What I really want is what you see below. One LINQ statement to get each type of IPerson. This works great until I call the method ;).

It makes sense as to why I'd get the error, but I am really struggling as to find a decent way to pull all IPerson objects from the DB and avoid putting switch statements all over my application.

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>();
    }

Above, there is a commented out return statement - that essentially does a .ToList() and forgoes the whole deferred execution thing, creating 2 SQL statements - not ideal.

like image 803
Dan Avatar asked Dec 31 '25 00:12

Dan


1 Answers

How about this:

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>());
}

It's not much better, but you get it in one call. Or, what I would do is something like this:

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();
}

But then again you get the switch-statement. Also, if you don't like to do a ToList() on the DB (if I recall correctly LinqToSQL doesn't support functions using constructors with variables) you can try adding the method GetPerson (I'd probably rename it though) to the Person class generated by LinqToSQL (partial class), but I'm not certain this is legal.

But how you're going to use the IQueryable coming from getPersons without using switch, I don't know.

like image 198
Alxandr Avatar answered Jan 01 '26 14:01

Alxandr