C# DbSet中的结果数<;张力>;

C# DbSet中的结果数<;张力>;,c#,entity-framework,linq,dbcontext,dbset,C#,Entity Framework,Linq,Dbcontext,Dbset,我正在浏览一些关于DBEntities和DbContext的示例代码。DbSet从数据库中提取的行数有限制吗?在下面的代码示例中,假设存在DbSet历史记录或DbSet日志,当创建dbcontext时,将dbcontext.logs或dbcontext.history数据库中是否存在所有日志?如果是这样,那么如果表有数百万行呢。在linq或任何udpates期间保存上下文时,它不会影响性能吗 public virtual DbSet<Course> Courses { get; se

我正在浏览一些关于DBEntities和DbContext的示例代码。DbSet从数据库中提取的行数有限制吗?在下面的代码示例中,假设存在
DbSet历史记录
DbSet日志
,当创建dbcontext时,将
dbcontext.logs
dbcontext.history
数据库中是否存在所有日志?如果是这样,那么如果表有数百万行呢。在linq或任何udpates期间保存上下文时,它不会影响性能吗

public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Standard> Standards { get; set; }
public virtual DbSet<Student> Students { get; set; }
public virtual DbSet<StudentAddress> StudentAddresses { get; set; }

实体框架不需要拉动任何行来执行插入,这是Add()方法和SaveChanged()所做的。它应该像您在SQL中那样向相关表中添加一行。

实体框架不需要拉动任何行来执行插入,而add()方法和SaveChanged()就是这样做的。它应该像您在SQL中那样向相关表中添加一行。

与您的示例一样,它不会“爆炸”

以下行基本上只向空的更改跟踪器添加一个项目:

 context.History.Add(history);
如果你愿意执行

context.History.ToList()
然后查询作为“select*from History”执行,如果它包含数百万行,您肯定会遇到性能问题

关键的一点是EF“足够聪明”,不会将内存中的所有内容作为一个整体加载。您可以附加探查器(或启用EF日志记录)以查看正在执行的实际查询。为了获得一些经验,你可以随便摆弄一下

如果使用调试器扩展集合,则基本上不应用任何筛选器,而是检索整个集合。由于导航属性被滥用,您甚至可以将整个数据库加载到内存中

字幕差异在
IQueryable
和其他类似
IEnumerable
的接口之间的差异范围内

当对象仍然是
IQueryable
时,实际的查询仍然要执行,并且可以使用过滤器进行扩展。正如我所说;一旦开始枚举,就会执行实际的查询,因此,未过滤的dbset将返回表中的所有行


还要注意提到的linq方法

.跳过

.拿


还有几个,如group、join、where等。

在您的示例中,它不会“爆炸”

以下行基本上只向空的更改跟踪器添加一个项目:

 context.History.Add(history);
如果你愿意执行

context.History.ToList()
然后查询作为“select*from History”执行,如果它包含数百万行,您肯定会遇到性能问题

关键的一点是EF“足够聪明”,不会将内存中的所有内容作为一个整体加载。您可以附加探查器(或启用EF日志记录)以查看正在执行的实际查询。为了获得一些经验,你可以随便摆弄一下

如果使用调试器扩展集合,则基本上不应用任何筛选器,而是检索整个集合。由于导航属性被滥用,您甚至可以将整个数据库加载到内存中

字幕差异在
IQueryable
和其他类似
IEnumerable
的接口之间的差异范围内

当对象仍然是
IQueryable
时,实际的查询仍然要执行,并且可以使用过滤器进行扩展。正如我所说;一旦开始枚举,就会执行实际的查询,因此,未过滤的dbset将返回表中的所有行


还要注意提到的linq方法

.跳过

.拿


还有一些,如group、join、where等。

您必须意识到,
DbSet
并不代表您的
学生集合,它代表数据库中的
学生表。这意味着您可以查询
学生的属性序列

如果需要,您可以查询完整的序列,但这将导致性能问题,如果不是内存问题的话

因此,如果您要求
学生
数据,您必须记住您将使用获取的数据:不要选择您已经知道其值的属性,不要选择您不打算使用的项目

例如:一个包含
学校
学生
的数据库,具有一对多关系,每个
学校
都有零个或多个
学生
,每个
学生
只上一所
学校

class School
{
     public int Id {get; set;}
     public string Name {get; set;}
     ...

     // every School has zero or more Students (one-to-many)
     public virtual ICollection<Student> Students {get; set;}
}

class Student
{
     public int Id {get; set;}
     public string Name {get; set;}
     ...

     // Every Student attends exactly one School, using foreign key:
     public int SchoolId {get; set;}
     public virtual School School {get; set;}
}
多浪费啊,先把所有牛津学校都招来,然后只保留这一所

此外:你得到了学校所有的学生,所有你使用的如果学校的Id

尽量长时间返回
IQueryable
,并让调用者决定如何处理返回的数据

也许他想做
ToList
,或者
Count
,或者
FirstOrDefault
。也许他只想要
Id
名称。只要您不知道这一点,就不要为他做决定,这只会降低代码的可重用性

始终使用
Select
选择属性,并仅选择实际计划使用的数据。仅当您计划更新包含的数据时才使用
Include

最后,如果你想访问所有的<代码>学生来显示它们,但是你不想一次就把所有的百万个学生都拿来,而是考虑用页面来获取它们。记住上次获取页面的最后一项的主键,并使用“.Where(item=>item.Id>lastFetchedPrimaryKey)。使用(pageSize)获取下一页,直到没有更多页面为止


这样,你可能会要求50个学生,而你只会显示其中的25个,但至少你的内存中没有100万学生。获取下一页的速度相当快,因为主键上已经有一个索引,并且获取的项目已经按主键排序。

您必须意识到
var mySchoolId = GetSchoolByLocation("Oxford")
    .Where(school => schoolStreet == "Main Street")
    .Select(school => school.Id)
    .FirstOrDefault();
var schools = dbContext.Schools.Where(school => ...)
    // Keep only the Schools that you actually plan to use:
    .Select(school => new
    {
        // only select the properties that you plan to use
        Id = school.Id,
        Name = school.Name,
        ...

        // Only the Students you plan to use:
        Students = school.Students.Where(student => ...)
            .Select(student => new
            {
                // Again, only the properties you plan to use
                Id = student.Id,
                Name = student.Name,

                // no need for the foreign key: you already know the value
                // SchoolId = student.SchoolId,
            }),
     });