2010-02-23 38 views
3

這是我的問題:我有一個由Employee和Student實現的IPerson。什麼我真的想要的是你在下面看到。一個LINQ語句來獲取每種類型的IPerson。這很好,直到我調用方法;)。這對我爲什麼會遇到錯誤是有道理的,但我真的很努力地找到一種體面的方式來從數據庫中提取所有IPerson對象,並避免將切換語句放在我的應用程序中。用一條LINQtoSQL語句返回不同的對象

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

如何:

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-statement。另外,如果你不喜歡在數據庫上執行ToList()(如果我記得LinqToSQL不支持使用具有變量的構造函數的函數),你可以嘗試添加GetPerson方法(我可能會重命名它)到由LinqToSQL(部分類)生成的Person類,但我不確定這是否合法。

但是,如何在不使用開關的情況下使用來自getPersons的IQueryable,我不知道。

+1

在這種情況下,交換機是合理的。第二種解決方案非常優雅。當另一種類型的IPerson對象被繼承時,交換機也可以處理場景。 – 2010-02-23 17:23:44

+0

我沒有基礎Person類 - 只有Student和Employee。我考慮添加一個Person類,但是我不確定當我想要返回一個特定的人時代碼會是什麼樣子。你在交換機上有什麼,你會根據Peron的基本類型創建一個新的IQueyrable 嗎?我真的希望有一種方法可以避免switch語句,但也許我只是太需要編碼器:)。感謝Alxandr。 – Dan 2010-02-23 17:32:11

+0

Alxandr,我很好奇「ret = ...」最終會成爲... – Dan 2010-02-24 03:15:16

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指着我在正確的方向!