首页 文章

Linq使用GroupBy和OrderByDescending在VM中加入两个表

提问于
浏览
0

我在EF 6.1中有两个表,我需要帮助加入它们来填充 OverDueEquipVM ,当我返回它时,groupBy抛出返回列表说它不是IEnumerable类型 .


Table 1: LaptopsTable 包含 Employee IdManagerIdDatesCheckedOut EqipType

Table 1: EmployeeTable 包含 Employee IdFirstNameLastNamePosition 员工/经理 .


我可以查询 Table 1: 所有项目逾期(超过一周),但是我的结果有 EmpIDMgrID 并且将一个分组的员工列表返回到视图集会抛出一个错误,它不是IEnumrable, how do I join this so that I can display the First + Last names as well? and group it by the emp names in descending order of overduedate 即在VM中添加名字,姓氏同样 .

db.LaptopsTable.Where(x => x.EmployeeId == userId) // loggedin user
           .Where(x => x.date >= checkOutDate.Date  // check overdue?
                                 && x.date < todaysDate.Date)
           .OrderByDescending(x => checkOutDate.Date)
           .GroupBy(x => x.EmployeeId)
           .TheOrderBy(x => x.EqipType).ToList();

public class OverDueEquipVM
{
   public int EmployeeId;
   public int ManagerId;

   public string EmployeeName; // First + last
   public string ManagerName;

   public date CheckOutDate;
   public string EqiupType;  // phone laptop etc
   public int EmployeeId;
}

1 回答

  • 1

    你提到的错误很简单:GroupBy的返回值是什么,ThenBy的输入值是多少?

    关于GroupBy中输出的顺序没有指定(因此也不保证),所以我认为在分组之前订购任何东西都没用 . 在分组过程之后你应该OrderBy和ThenBy .

    关于您的OverDueEquipVM .

    看来你想要来自 Employee 的所有 Laptops 的列表与给定的 userId 已过期 . 除了一些 Laptop 信息之外,您还需要 FirstName 和拥有 LaptopEmployeeLastName 以及hist ManagerId .

    由于你的GroupBy语句,似乎 Employee 和_1737450之间存在一对多的关系:每个 Employee 都有零个或多个 Laptops ,而每个 Laptop 都属于使用EmployeeId的一个Employee` .

    我认为 ManagerLaptop 之间也存在一对多的关系:每个 Manager 管理零个或多个 Laptops ,并且每个 Laptop 由一个 Manager 管理,使用外键 ManagerId

    因为你的短语:“员工/经理”我不确定每个员工是否都有经理 . 我假设你想要最终结果的笔记本电脑经理 .

    如果您根据Entity Framework One-To-Many conventions配置您的Employee / Laptop / Manager课程,您可能会遇到以下情况:

    class Employee
    {
        public int Id {get; set;}    // primary key
    
        // every Employee has zero or more Laptops:
        public virtual ICollection<Laptop> Laptops {get; set;}
    
        // other properties:
        public string FirstName {get; set;}
        public string LastName {get; set;}
        ...
    }
    class Manager
    {
        public int Id {get; set;}    // primary key
    
        // every Manager manages zero or more Laptops:
        public virtual ICollection<Laptop> Laptops {get; set;}
    
        // other properties:
        public string FirstName {get; set;}
        public string LastName {get; set;}
        ...
    }
    
    class Laptop
    {
        public int Id {get; set;}    // primary key
    
        // every Laptop is owned by exactly one Employee using foreign key:
        public int EmployeeId {get; set;}
        public Employee Employee {get; set;}
    
        // every Laptop is managed by exactly one Manager using foreign key:
        public int ManagerId {get; set;}
        public Manager Manager {get; set;}
    
        // other properties:
        public DateTime Date {get; set;}
        public string  EquipmentType {get; set;}
    }
    

    现在,给定userId,checkoutDate和todaysDate,您希望此用户拥有的所有笔记本电脑都具有checkOutDate和todaysDate之间的日期 . 每台笔记本电脑都需要这台笔记本电脑所有者的名字和姓氏,以及这台笔记本电脑的管理员的名字和姓氏 .

    有几个问题:

    您不希望使用checkoutDate和todaysDate的DateTime值,而是使用Date属性 . 通常你会使用DateTime.Date . 但Ling不支持IQueryable中的此功能 .

    最简单的方法是在linq语句中使用之前提取日期:

    checkoutDate = checkoutDate.Date;
    todaysDate = todaysDate.Date;
    // TODO: create a LINQ query
    

    另一种方法是使用DbFunctions.TruncateTime

    另一个问题是您想要连接Employee和Manager的FristName和LastName . 实体框架不支持String.Concat . 最好的方法是记住OverDueEquipm中的FirstName和LastName,并添加一个FullName属性:

    class Name
    {
        public string FirstName {get; set;}
        public string LastName {get; set;}
        public string FullName
        {
            get {return this.FirstName + ' ' + this.LastName;}
        }
    }
    
    class Employee
    {
        public Name Name {get; set;}
        ...
    }
    class Manager
    {
        public Name Name {get; set;}
        ...
    }
    

    好消息是,如果您想更改名称的想法,例如添加中间名,或想要使用缩写或其他更改,您不必更改您的员工或经理 .

    如果你真的不想引入一个Name类,你将不得不进行串联AsEnumerable .

    完成此操作后,您的查询将很容易:

    var result = myDbContext.Laptops
        .Where(lapto => laptop.EmployeeId == userId
        && checkoutDate <= laptop.Date 
        && laptop.Date <= todaysDate)
        .Select(laptop => new OverdueEquipVm
        {
            EmployeeId = laptop.EmployeeId,
            MangerId = laptop.MangerId,
            Date = laptop.CheckoutDate,
            EquipmentType = laptop.EquipmentType,
    
            EmployeeName = new Name
            {
                FirstName = laptop.Employee.FirstName,
                LastName = laptop.Employee.LastName,
            },
            ManagerName  = new Name
            {
                FirstName = laptop.Manager.FirstName,
                LastName = laptop.Manager.LastName,
            },
        });
    

相关问题