使用一个LINQtoSQL语句返回不同的对象

时间:2010-02-23 16:29:08

标签: c# asp.net linq linq-to-sql

这是我的问题:我有一个由员工和学生实施的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>();
    }

上面,有一个注释掉的return语句 - 基本上是一个.ToList()并且放弃了整个延迟执行的事情,创建了2个SQL语句 - 并不理想。

感谢任何帮助!

2 个答案:

答案 0 :(得分:2)

这个怎么样:

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

但是你又得到了switch语句。另外,如果您不喜欢在DB上执行ToList()(如果我没记错LinqToSQL不支持使用带变量的构造函数的函数),您可以尝试添加方法GetPerson(我可能会重命名)由LinqToSQL(部分类)生成的Person类,但我不确定这是否合法。

但是我不知道如何在不使用开关的情况下使用来自getPersons的IQueryable,我不知道。

答案 1 :(得分:0)

这是我最终做的事情:

存储库

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指出我正确的方向!