如何避免在C#LINQ中连续嵌套.Any

时间:2016-04-13 12:55:35

标签: c# entity-framework linq

我有一个Collection List BossList。因为我使用嵌套的.Any()来确定条件。现在,我的实际项目中的性能非常慢。请考虑以下示例源代码。

void Main()
{

    List<Boss> BossList = new List<Boss>()
    {
        new Boss()
        {
            ID = 101,
            Name = "Harry",
            Department = "Development",
            Gender = "Male",
            Role = "Manager",
            Employees = new List<Person>() {
                new Person() {
                    ID = 101, 
                    SID = 102, 
                    Name = "Peter", 
                    Department = "Development", 
                    Gender = "Male", 
                    Role = "Assistant",
                    PayInfo = new List<PayrollInfo>()
                    {
                        new PayrollInfo() { Monthof2015 = 1, NetWorkingDays = 24, AbsentDays = 6 },
                        new PayrollInfo() { Monthof2015 = 2, NetWorkingDays = 23, AbsentDays = 3 },
                        new PayrollInfo() { Monthof2015 = 3, NetWorkingDays = 20, AbsentDays = 2 },
                        new PayrollInfo() { Monthof2015 = 4, NetWorkingDays = 22, AbsentDays = 1 },
                        new PayrollInfo() { Monthof2015 = 5, NetWorkingDays = 24, AbsentDays = 4 },
                        new PayrollInfo() { Monthof2015 = 6, NetWorkingDays = 26, AbsentDays = 6 },
                        new PayrollInfo() { Monthof2015 = 7, NetWorkingDays = 25, AbsentDays = 4 },
                        new PayrollInfo() { Monthof2015 = 8, NetWorkingDays = 21, AbsentDays = 3 },
                        new PayrollInfo() { Monthof2015 = 9, NetWorkingDays = 20, AbsentDays = 8 },
                        new PayrollInfo() { Monthof2015 = 10, NetWorkingDays = 25, AbsentDays = 9 },
                        new PayrollInfo() { Monthof2015 = 11, NetWorkingDays = 24, AbsentDays = 4 },
                        new PayrollInfo() { Monthof2015 = 12, NetWorkingDays = 26, AbsentDays = 1 },
                    }
                },
                new Person() {
                    ID = 101, 
                    SID = 103, 
                    Name = "Emma Watson", 
                    Department = "Development", 
                    Gender = "Female", 
                    Role = "Assistant",
                    PayInfo = new List<PayrollInfo>() {
                        new PayrollInfo() { Monthof2015 = 1, NetWorkingDays = 24, AbsentDays = 5 },
                        new PayrollInfo() { Monthof2015 = 2, NetWorkingDays = 23, AbsentDays = 3 },
                        new PayrollInfo() { Monthof2015 = 3, NetWorkingDays = 20, AbsentDays = 3 },
                        new PayrollInfo() { Monthof2015 = 4, NetWorkingDays = 22, AbsentDays = 4 },
                        new PayrollInfo() { Monthof2015 = 5, NetWorkingDays = 24, AbsentDays = 1 },
                        new PayrollInfo() { Monthof2015 = 6, NetWorkingDays = 26, AbsentDays = 9 },
                        new PayrollInfo() { Monthof2015 = 7, NetWorkingDays = 25, AbsentDays = 4 },
                        new PayrollInfo() { Monthof2015 = 8, NetWorkingDays = 21, AbsentDays = 3 },
                        new PayrollInfo() { Monthof2015 = 9, NetWorkingDays = 20, AbsentDays = 1 },
                        new PayrollInfo() { Monthof2015 = 10, NetWorkingDays = 25, AbsentDays = 2 },
                        new PayrollInfo() { Monthof2015 = 11, NetWorkingDays = 24, AbsentDays = 1 },
                        new PayrollInfo() { Monthof2015 = 12, NetWorkingDays = 26, AbsentDays = 1 },
                    }
                },

            }
        },
        new Boss()
        {
            ID = 104,
            Name = "Raj",
            Department = "Development",
            Gender = "Male",
            Role = "Manager",
            Employees = new List<Person>()
            {
                new Person() {
                    ID = 104, 
                    SID = 105, 
                    Name = "Kaliya", 
                    Department = "Development", 
                    Gender = "Male", 
                    Role = "Assistant",
                    PayInfo = new List<PayrollInfo>() {
                        new PayrollInfo() { Monthof2015 = 1, NetWorkingDays = 24, AbsentDays = 6 },
                        new PayrollInfo() { Monthof2015 = 2, NetWorkingDays = 23, AbsentDays = 3 },
                        new PayrollInfo() { Monthof2015 = 3, NetWorkingDays = 20, AbsentDays = 2 },
                        new PayrollInfo() { Monthof2015 = 4, NetWorkingDays = 22, AbsentDays = 1 },
                        new PayrollInfo() { Monthof2015 = 5, NetWorkingDays = 24, AbsentDays = 4 },
                        new PayrollInfo() { Monthof2015 = 6, NetWorkingDays = 26, AbsentDays = 6 },
                        new PayrollInfo() { Monthof2015 = 7, NetWorkingDays = 25, AbsentDays = 4 },
                        new PayrollInfo() { Monthof2015 = 8, NetWorkingDays = 21, AbsentDays = 3 },
                        new PayrollInfo() { Monthof2015 = 9, NetWorkingDays = 20, AbsentDays = 8 },
                        new PayrollInfo() { Monthof2015 = 10, NetWorkingDays = 25, AbsentDays = 9 },
                        new PayrollInfo() { Monthof2015 = 11, NetWorkingDays = 24, AbsentDays = 4 },
                        new PayrollInfo() { Monthof2015 = 12, NetWorkingDays = 26, AbsentDays = 1 },
                    }
                },
                new Person() {
                    ID = 104, 
                    SID = 103, 
                    Name = "Emma Watson", 
                    Department = "Development", 
                    Gender = "Female", 
                    Role = "Assistant",
                    PayInfo = new List<PayrollInfo>() {
                        new PayrollInfo() { Monthof2015 = 1, NetWorkingDays = 24, AbsentDays = 5 },
                        new PayrollInfo() { Monthof2015 = 2, NetWorkingDays = 23, AbsentDays = 3 },
                        new PayrollInfo() { Monthof2015 = 3, NetWorkingDays = 20, AbsentDays = 3 },
                        new PayrollInfo() { Monthof2015 = 4, NetWorkingDays = 22, AbsentDays = 4 },
                        new PayrollInfo() { Monthof2015 = 5, NetWorkingDays = 24, AbsentDays = 1 },
                        new PayrollInfo() { Monthof2015 = 6, NetWorkingDays = 26, AbsentDays = 9 },
                        new PayrollInfo() { Monthof2015 = 7, NetWorkingDays = 25, AbsentDays = 4 },
                        new PayrollInfo() { Monthof2015 = 8, NetWorkingDays = 21, AbsentDays = 3 },
                        new PayrollInfo() { Monthof2015 = 9, NetWorkingDays = 20, AbsentDays = 1 },
                        new PayrollInfo() { Monthof2015 = 10, NetWorkingDays = 25, AbsentDays = 2 },
                        new PayrollInfo() { Monthof2015 = 11, NetWorkingDays = 24, AbsentDays = 1 },
                        new PayrollInfo() { Monthof2015 = 12, NetWorkingDays = 26, AbsentDays = 1 },
                    }
                },

            },
        },
        new Boss()
        {
            ID = 102,
            Name = "Peter",
            Department = "Development",
            Gender = "Male",
            Role = "Manager",
            Employees = new List<Person>()
            {
                new Person() {
                    ID = 102, 
                    SID = 105, 
                    Name = "Kaliya", 
                    Department = "Development", 
                    Gender = "Male", 
                    Role = "Assistant",
                    PayInfo = new List<PayrollInfo>() {
                        new PayrollInfo() { Monthof2015 = 1, NetWorkingDays = 24, AbsentDays = 6 },
                        new PayrollInfo() { Monthof2015 = 2, NetWorkingDays = 23, AbsentDays = 3 },
                        new PayrollInfo() { Monthof2015 = 3, NetWorkingDays = 20, AbsentDays = 2 },
                        new PayrollInfo() { Monthof2015 = 4, NetWorkingDays = 22, AbsentDays = 1 },
                        new PayrollInfo() { Monthof2015 = 5, NetWorkingDays = 24, AbsentDays = 4 },
                        new PayrollInfo() { Monthof2015 = 6, NetWorkingDays = 26, AbsentDays = 6 },
                        new PayrollInfo() { Monthof2015 = 7, NetWorkingDays = 25, AbsentDays = 4 },
                        new PayrollInfo() { Monthof2015 = 8, NetWorkingDays = 21, AbsentDays = 3 },
                        new PayrollInfo() { Monthof2015 = 9, NetWorkingDays = 20, AbsentDays = 8 },
                        new PayrollInfo() { Monthof2015 = 10, NetWorkingDays = 25, AbsentDays = 9 },
                        new PayrollInfo() { Monthof2015 = 11, NetWorkingDays = 24, AbsentDays = 4 },
                        new PayrollInfo() { Monthof2015 = 12, NetWorkingDays = 26, AbsentDays = 1 },
                    }
                },
                new Person() {
                    ID = 102, 
                    SID = 103, 
                    Name = "Emma Watson", 
                    Department = "Development", 
                    Gender = "Female", 
                    Role = "Assistant",
                    PayInfo = new List<PayrollInfo>() {
                        new PayrollInfo() { Monthof2015 = 1, NetWorkingDays = 24, AbsentDays = 5 },
                        new PayrollInfo() { Monthof2015 = 2, NetWorkingDays = 23, AbsentDays = 3 },
                        new PayrollInfo() { Monthof2015 = 3, NetWorkingDays = 20, AbsentDays = 3 },
                        new PayrollInfo() { Monthof2015 = 4, NetWorkingDays = 22, AbsentDays = 4 },
                        new PayrollInfo() { Monthof2015 = 5, NetWorkingDays = 24, AbsentDays = 1 },
                        new PayrollInfo() { Monthof2015 = 6, NetWorkingDays = 26, AbsentDays = 9 },
                        new PayrollInfo() { Monthof2015 = 7, NetWorkingDays = 25, AbsentDays = 4 },
                        new PayrollInfo() { Monthof2015 = 8, NetWorkingDays = 21, AbsentDays = 3 },
                        new PayrollInfo() { Monthof2015 = 9, NetWorkingDays = 20, AbsentDays = 1 },
                        new PayrollInfo() { Monthof2015 = 10, NetWorkingDays = 25, AbsentDays = 2 },
                        new PayrollInfo() { Monthof2015 = 11, NetWorkingDays = 24, AbsentDays = 1 },
                        new PayrollInfo() { Monthof2015 = 12, NetWorkingDays = 26, AbsentDays = 1 },
                    }
                }
            }
        }
    };

    BossList.Where(i => i.Employees.Any(j => j.PayInfo.Any(s => s.AbsentDays >6))).Select(m => m.Name).Dump();
}

模型类是

public class Person
{
    public int ID { get; set; }
    public int SID { get; set; }
    public string Name { get; set; }
    public string Department { get; set; }
    public string Gender { get; set; }
    public string Role { get; set; }
    public List<PayrollInfo> PayInfo { get; set; }
}

public class Boss
{
    public int ID { get; set; }
    public int SID { get; set; }
    public string Name { get; set; }
    public string Department { get; set; }
    public string Gender { get; set; }
    public string Role { get; set; }
    public List<Person> Employees { get; set; }
}

public class PayrollInfo
{
    public int Monthof2015 { get; set; }
    public int NetWorkingDays { get; set; }
    public int AbsentDays { get; set; }
}

主LINQ查询

BossList.Where(i => i.Employees
                      .Any(j => j.PayInfo
                                 .Any(s => s.AbsentDays >6)))
        .Select(m => m.Name);

在我的主项目中,它包含6个嵌套的.Any()。在这里,由于代码冗长,我无法创建。

我在EF中使用查询作为IQueryable。该数据库包含超过1000K的记录。

请建议我,是否有任何有效的方法可以最大限度地提高性能?

3 个答案:

答案 0 :(得分:2)

执行此操作的最佳方法可能仍然是使用BossList作为起点,但要构建一个Ids列表,其中应显示其ID:

db.BossList.Where(b => db.PayrollInfos.Where(s => s.AbsentDays >6)
                                .Select(p => p.Employee.BossId)
                   .Contains(b.BossId));

在SQL中,这可能会转化为一个整洁有效的EXISTS查询。

请注意,我假设您的真实模型中有后向引用(PayrollInfos.Employee),并且我使用了占位符BossId,您应该用实际的键属性替换它。从您的示例中可以清楚地了解引用IDSID的工作原理。

db是您的DbContext个实例。

更多地解释这种方法:根据我的经验,通常最好使用包含您所追求的结果的集合(即Bosslist)开始查询,然后添加过滤结果的谓词。其他答案以PayrollInfo开头。没关系,但最后你需要分组或Distinct删除重复项。通常,这不会使查询计划优于相对简单的table WHERE EXSIST( subqyery )

答案 1 :(得分:1)

如果您将“外键”等内容添加到“父母”中,该怎么办?在每个实体?

public class PayrollInfo
{
    public int Monthof2015 { get; set; }
    public int NetWorkingDays { get; set; }
    public int AbsentDays { get; set; }
    public Person Person { get; set; }
}

当您在构造函数中创建Person - 参数时可以设置新属性:

public Person(IList<PayrollInfo> list)
{
    this.PayInfo = list;
    foreach(var pay in this.PayInfo)
        pay.Person = this;
}

或者只定义一个设置PayInfo的方法。随你喜欢。 然后为Person和Boss做同样的事情。 然后你可以像

那样写smth
AllPayrollInfos.Where(x => x.Days > 6).GroupBy(x => x.Person.Boss).Select(x => x.Key).ToList();

答案 2 :(得分:1)

假设这是一个淡化的EF查询;我会将您的选择反转为以PayrollInfo开头,然后选择Boss名称:

Boss Boss = new Boss
{
    ID = 101,
    Name = "Harry",
    Department = "Development",
    Gender = "Male",
    Role = "Manager",
};
Person Person = new Person() { ID = 101, SID = 102, Name = "Peter", Department = "Development", Gender = "Male", Role = "Assistant", Boss = Boss};
List<PayrollInfo> PayrollInfoList = new List<UserQuery.PayrollInfo>
{
    new PayrollInfo() { Monthof2015 = 1, NetWorkingDays = 24, AbsentDays = 6, Person = Person },
    new PayrollInfo() { Monthof2015 = 2, NetWorkingDays = 23, AbsentDays = 3, Person = Person },
    new PayrollInfo() { Monthof2015 = 3, NetWorkingDays = 20, AbsentDays = 2, Person = Person },
    new PayrollInfo() { Monthof2015 = 4, NetWorkingDays = 22, AbsentDays = 1, Person = Person },
    new PayrollInfo() { Monthof2015 = 5, NetWorkingDays = 24, AbsentDays = 4, Person = Person },
    new PayrollInfo() { Monthof2015 = 6, NetWorkingDays = 26, AbsentDays = 6, Person = Person },
    new PayrollInfo() { Monthof2015 = 7, NetWorkingDays = 25, AbsentDays = 4, Person = Person },
    new PayrollInfo() { Monthof2015 = 8, NetWorkingDays = 21, AbsentDays = 3, Person = Person },
    new PayrollInfo() { Monthof2015 = 9, NetWorkingDays = 20, AbsentDays = 8, Person = Person },
    new PayrollInfo() { Monthof2015 = 10, NetWorkingDays = 25, AbsentDays = 9, Person = Person },
    new PayrollInfo() { Monthof2015 = 11, NetWorkingDays = 24, AbsentDays = 4, Person = Person },
    new PayrollInfo() { Monthof2015 = 12, NetWorkingDays = 26, AbsentDays = 1, Person = Person },
};


PayrollInfoList.Where(p => p.AbsentDays > 6).Select(p => p.Person.Boss.Name).Distinct().Dump();