C#优化Linq查询:使用

时间:2019-02-18 16:17:10

标签: c# entity-framework linq .net-core .net-core-2.0

如何优化以下查询?我们正在审查数据库中的实体框架查询,并尝试学习。

        using (var context = new DataDbContext())
        {
            var query = (from u in content.Parents
                         where u.Children.Any(y = y.Age > 13)
                         select u);

            foreach (var parent in query.ToList())
            {
                foreach (var children in owner.Children)
                {
                    children.IsTeenager= true;
                }
            }
            context.SaveChanges();
        }

5 个答案:

答案 0 :(得分:3)

没有什么好方法可以简化您在这里所做的事情。 EF倾向于将您推向从数据存储中读取一堆数据,在本地更新实体然后将这些更改写回的路径。这显然很慢。但是,您要在此处进行的操作是获取所有子项并设置IsTeenager属性,这样您甚至不必关心Parent对象,只需执行以下操作即可:

var children = context.Children.Where(c => c.Age < 13);

foreach(var child in children)
{
    child.IsTeenager = true;
}

context.SaveChanges();

当然,使用原始SQL可以更轻松地完成此操作。例如:

context.Database.ExecuteSqlCommand("UPDATE Children SET IsTeenager = 1 WHERE Age < 13");

答案 1 :(得分:1)

没有太多要优化的地方,可以减少代码。逻辑有点奇怪

using (var context = new DataDbContext())
{
    foreach (var child in content.Parents.Where(o => o.Children.Any(x => x.Age > 13)).SelectMany(o => o.Children))
    {
        children.IsTeenager= true;
    }

    context.SaveChanges();
}

using (var context = new DataDbContext())
{
    var parents = content.Parents.Where(o => o.Children.Any(x => x.Age > 13));
    foreach (var child in parents.SelectMany(o => o.Children))
    {
        children.IsTeenager= true;
    }

    context.SaveChanges();
}

答案 2 :(得分:1)

(from u in content.Parents
  where u.Children.Any(y = y.Age > 13)
  select u);

这似乎是一个错误。如果Parent有一个14岁的孩子,另一个9岁的孩子,都将IsTeenager设置为true。相反,如果他们只有一个13岁的孩子,那么这个孩子就不会将“少年”设置为true。

如果可能的话,我将IsTeenager设为计算属性,而不是存储值

public bool IsTeenager => Age >= 13 && Age <= 19

那我根本就不必调用查询。

无法将查询更改为

content.Parents.SelectMany(o => o.Children).Where(o => o.Age >= 13 && o.Age <= 19)

可能我可以完全像这样跳过间接操作。

content.Children.Where(o => o.Age >= 13 && o.Age <= 19)

取决于数据库的结构。我真的需要和父母一起去吗?

除非我知道运行查询时IsTeenager总是错误的,否则我可以过滤那些不需要它的内容,设置为:

content.Parents.SelectMany(o => o.Children).Where(o => !o.IsTeenager && o.Age >= 13 && o.Age <= 19)

content.Children.Where(o => !o.IsTeenager && o.Age >= 13 && o.Age <= 19)

答案 3 :(得分:0)

我之前在您的评论中看到了以下内容(已被删除):

  

这是我几个月前遇到的求职面试问题,甚至不确定

如果我在求职面试中向某人问这个问题,我希望他们能将以下情况告知我:


  1. 年龄和IsTeenager应该依赖于每个单独的实体,而不是对集合进行计算。
  2. 您应确保该人/孩子的出生日期保持不变,而不是年龄。否则,您不知道实体的年龄何时更改,因为该年龄仅在系统中捕获该实体的日期和时间有效。
  3. IsTeeneger不应该保留,而应基于“出生日期”值派生。如果仅在c#代码中检查过它,而不必查询它,则将其设置为模型唯一的getter字段,该字段在Sql中映射。如果需要对其进行查询,请使其成为数据库架构的计算列。对Age也应这样做!
  4. 最好将父级和子级建模为具有一对多递归关系的子级的子级。这样,您也可以让有孩子的大父母生孩子。

仅限型号

public class PersonModel
{
    public DateTime BirthDate { get; set; }
    public int Age
    {
        get
        {
            var today = DateTime.Today;
            // Calculate the age.
            var age = today.Year - BirthDate.Year;
            // Go back to the year the person was born in case of a leap year
            if (BirthDate > today.AddYears(-age)) age--;
            return age;
        }
    }
    public bool IsTeenager
    {
        get
        {
            return Age >= 13 && Age < 20;
        }
    }
}

映射到计算列

public class PersonModel
{
    public DateTime BirthDate { get; set; }
    public int Age { get; set; } // should be computed and mapped from sql
    public bool IsTeenager { get; set; } // should be computed and mapped from sql
}

答案 4 :(得分:0)

要使用Entity Framework更新数据时,必须先将其检索到内存中(通过急切加载或延迟加载),然后进行修改。
有时会导致N + 1问题。这意味着对数据库服务器的N + 1次调用。而且,如果您使用某些基于云的托管(例如Azure或AWS),则将按请求收费。因此,这在财务上也将是昂贵的。

在您的情况下,我希望在“是”实体框架中执行此操作,但要使用存储过程。使用普通查询,但我不建议您采用这种方式。

使用存储过程将使您免于将数据带入内存并使用1个数据库调用获得结果的麻烦。