C# Linq 查询过滤子集合

3

你好,

我有一个如下的模型类

    public class EmployeeModel
    {
      [Key]
     public int employeeId{get;set;}
     public string Fullname {get;set;}
     public string Address{get;set;}
     public ICollection<PaymentModel> Payments {get;set;}
    }


    public class PaymentModel
    {

      [Key]
     public int PaymentId{get; set;}
     public int employeeId{get; set;}
     public decimal PaymentAmount{get; set;}
      public int IsPosted {get; set;}
      public virtual EmployeeModel Employee {get; set;}

    }

我想使用 LINQ 查询员工名单和他们的付款清单。我的代码如下:
dbcontext db = new dbcontext();
var listing = from d in db.Employees
              .include("Payments")
               select d;

这个列表展示了所有员工及其所有的薪资支付。但我需要筛选每个员工支付的IsPosted = 1。
所以作为初始答案,我会编写以下代码;
dbcontext db = new dbcontext();
List<EmployeeModel> FinalList = new List<EmployeeModel>();
var listingofEmp = db.employee.ToList();

foreach(EmployeeModel emp in listingofEmp){
emp.Payments= db.payments.where(x => x.IsPosted == 1).ToList();
FinalList.Add(emp);
}

我的问题是,是否有其他更简单的编码方式?例如这样。
    dbcontext db = new dbcontext();
    var listing = from d in db.Employees
                  .include(d => x.Payments.IsPosted == 1)
                   select d;

我目前正在使用Entity Framework 5。

我已经进行了相关研究,发现它对我不起作用链接

希望有人能帮助我。

感谢大家的帮助。

3个回答

7
您所需求的功能不是原生支持的,因此没有更简单的方法,但肯定有更高效的方法,因为您当前的代码执行了N + 1个数据库查询。
一种更好的方法是使用匿名类型投影一次性检索员工和相关的筛选付款,并像您的方法一样在内存中创建最终结果。例如:
var listing = 
    db.Employees.Select(employee => new
    {
        employee,
        payments = employee.Payments.Where(p => p.IsPosted == 1)
    })
    .AsEnumerable() // Switch to LINQ to Objects
    .Select(r =>
    {
        r.employee.Payments = r.payments.ToList();
        return r.employee;
    })
    .ToList();

它像魔法一样运行得很好!感谢您的帮助,伊万先生。伊万先生,我可以问一下在哪里可以学习更多关于LINQ吗?有没有相关链接或书籍?希望能从您那里听到回复,拜托了伊万先生;(... - Neil
嗨,尼尔,我真的不知道该给你什么建议。我相信有很多关于LINQ的好书/链接,但我个人是通过MSDN主题和主要的实验来学习的。请注意,不同的LINQ实现具有特定性,因此例如上述内容可能适用于最新的EF Core,也可能不适用。 - Ivan Stoev
在 EF6 中是否有使用 LINQ 的等效方法来实现这个?我尝试了相同的逻辑,但它没有过滤子集合。 - overloading
@overloading 它应该在EF6中工作。只需确保集合导航属性不是“virtual”,或者禁用了延迟加载,因为延迟加载将覆盖过滤。 - Ivan Stoev
@IvanStoev,太棒了!在第一个Select中,它正在过滤付款并为其创建一个变量。在第二个Select中,它将该过滤列表设置为父级列表。太聪明了! - Alex

1

它可能是一个不错的替代方案

var listing = from d in db.Payments
              .include("Employees")
              .where d.IsPosted == 1
               select d.Employees;

(未经测试,请修正错误)

从支付开始,筛选已发布的is posted=1,然后选择相关的员工


谢谢 @Danilo Calzetta 的即时回答。我会尝试这个 :D - Neil
您好,@Danilo Calzetta 先生,还有其他方法吗? 我需要绑定员工列表,然后是其付款子报表。这种方法会更加困难,因为我需要循环每个付款并将其分组到单个列表中,以便将其绑定到 WPF UI 的 List view 上。 - Neil
@Neil,请看一下我的示例查询,它返回了一个员工列表,因为选择了“d.employees”而不是“d”。 - danilonet

0
尝试像这样做:它将为您提供一个匿名类型列表,其中包含员工及其付款信息。
using (dbcontext ctx = new dbcontext())
{
    ctx.Connection.Open();

    var result = (from e in ctx.Employees
                  join p in ctx.Payments on e.employeeId equals p.employeeId
                  where p.IsPosted == 1
                  select new
                  {
                      Employee = e,
                      Payments = p
                  }).ToList();

    ctx.Connection.Close();
}

嗨@Paul,我该如何使用这个结果?我想将它封装成员工列表,以便可以将其绑定到我的WPF UI上。对于这个初学者问题,很抱歉。 - Neil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接