【问题标题】:Return different objects with one LINQtoSQL statement使用一个 LINQtoSQL 语句返回不同的对象
【发布时间】:2010-02-23 16:29:08
【问题描述】:

我有一个由员工和学生实施的 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 语句 - 不理想。

【问题讨论】:

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


    【解决方案1】:

    这个怎么样:

    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 语句。另外,如果您不喜欢在数据库上执行 ToList() (如果我没记错的话 LinqToSQL 不支持使用带有变量的构造函数的函数),您可以尝试添加方法 GetPerson (我可能会重命名它)到LinqToSQL 生成的 Person 类(部分类),但我不确定这是否合法。

    但我不知道你将如何使用来自 getPersons 的 IQueryable 而不使用 switch。

    【讨论】:

    • 在这种情况下切换是合理的。第二种解决方案非常优雅。该开关还可以处理继承另一种类型的 IPerson 对象的情况。
    • 我没有基本的 Person 类 - 只有 Student 和 Employee。我考虑添加一个 Person 类,但我不确定当我想返回一个特定的人时代码会是什么样子。您的交换机中有什么,您会根据基本 Peron 的类型创建一个新的 IQueyrable 吗?我真的希望有一种方法可以避免 switch 语句,但也许我只是太需要编码器了 :)。谢谢亚历山大。
    • 有趣的是,在我问了这个问题之后,我再次查看了您的代码并且有一个“哦,duh”的时刻。谢谢:)
    【解决方案2】:

    这是我最终做的:

    存储库

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-14
      • 2015-08-14
      • 1970-01-01
      • 1970-01-01
      • 2015-09-13
      • 1970-01-01
      相关资源
      最近更新 更多