C# DbSet中的结果数<;张力>;
我正在浏览一些关于DBEntities和DbContext的示例代码。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
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,
}),
});