EF Core 在对现有查询添加查询时附加所有实体 [重复]
Posted
技术标签:
【中文标题】EF Core 在对现有查询添加查询时附加所有实体 [重复]【英文标题】:EF Core attaching all entities while adding query on existing query [duplicate] 【发布时间】:2022-01-13 08:49:06 【问题描述】:我有一些复杂的场景,但我会在这里简单地展示它们。所以,我的上下文类非常简单:
public class AppDbContext : DbContext
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
optionsBuilder.UseSqlServer("data source=DILSHODKPC;integrated security=True;Database=ODataTEst; MultipleActiveResultSets=true");
protected override void OnModelCreating(ModelBuilder modelBuilder)
var student = modelBuilder.Entity<Student>();
student.HasKey(s => s.Id);
public IQueryable<T> GetEntities<T>() where T : class
return Set<T>();
我的模型也很简单:
public class Student
public Guid Id get; set;
public string Name get; set;
public int Score get; set;
我在数据库中有 8 条记录:
我的问题是当我向现有实体框架添加查询时正在跟踪所有实体。看两个场景:
场景 1:
AppDbContext appDbContext = new AppDbContext();
var query1 = appDbContext.GetEntities<Student>().Where(s => s.Score > 3);
var query2 = query1.Where(s => s.Name == "Messi");
var loadedEntitiesCount = query2.ToList().Count();//Count is 4. It is good
var trackedEntitiesCount = appDbContext.ChangeTracker.Entries<Student>().Select(e => e.Entity).Count();//Count is 4. It is good
在这种情况下,一切都在意料之中。
场景 2:
static void Main(string[] args)
AppDbContext appDbContext = new AppDbContext();
var query1 = GetFirstQuery(appDbContext);
var query2 = query1.Where(s => s.Name == "Messi");
var loadedEntitiesCount = query2.ToList().Count();//Count is 4. It is good
var trackedEntitiesCount = appDbContext.ChangeTracker.Entries<Student>().Select(e => e.Entity).Count();//Count is 8. Confusing
static IEnumerable<Student> GetFirstQuery(AppDbContext appDbContext)
return appDbContext.GetEntities<Student>().Where(s => s.Score > 3);
在这种情况下,跟踪的实体数为 8。我没想到
场景 3:
AppDbContext appDbContext = new AppDbContext();
var query1 = GetFirstQuery(appDbContext).AsQueryable();
var query2 = query1.Where(s => s.Name == "Messi");
var loadedEntitiesCount = query2.ToList().Count();//Count is 4. It is good
var trackedEntitiesCount = appDbContext.ChangeTracker.Entries<Student>().Select(e => e.Entity).Count();//Count is 4. It is good
跟踪的实体数为 4。
问题是为什么 ef 跟踪场景 2 中的所有实体?这是预期的吗?在具有不同类型集合的现有查询上添加查询的最佳实践是什么? (IEnumerable, IQueryable)
【问题讨论】:
【参考方案1】:一般来说,如果您不想跟踪对象,您可以在查询时调用.AsNoTracking()
。那么这个查询的结果就不会被跟踪了。
在您的具体情况下:
static IEnumerable<Student> GetFirstQuery(AppDbContext appDbContext)
这意味着查询在此处结束,因为您返回一个IEnumerable
。然后结果将在您的应用程序的内存中进一步过滤,因此您得到正确的结果,但所有数据都将从数据库中查询。
如果您希望查询继续进行并将进一步的过滤器或表达式传输到数据库而不是在应用程序的内存中执行,请使用 IQueryable<>
:
static IQueryable<Student> GetFirstQuery(AppDbContext appDbContext)
【讨论】:
“查询到此结束”是什么意思?在我调用 ToList 之前,它不会加载到内存中。 GetFirstQuery 返回类型为 IEnumerableappDbContext.GetEntities<Student>().Where(s => s.Score > 3)
完整运行(并且所有 8 个实体都由该 where 子句匹配),然后您在本地将其过滤为梅西.Where(s => s.Name == "Messi");
。
Caius 是正确的。我不是在谈论延迟执行,你是对的,它发生在你的 ToList 调用中。我说的是你的链的一部分正在处理 IQueryable。这些部分被转换成 SQL 并在数据库上处理。部分在 IEnumerable 上,这些发生在内存中。只要您希望链的延续也能对数据库进行操作,您就需要将其保留为 IQueryable。
本质上,如果您使用 GetFirstQuery 返回 IEnumerable 执行此操作,就像在执行 appDbContext.GetEntities<Student>().Where(s => s.Score > 3).AsEnumerable().Where(s => s.Name == "Messi");
- 第二个 Where 枚举可枚举,触发第一个查询运行;这两个 Where 不像他们通常那样在复合中行动以上是关于EF Core 在对现有查询添加查询时附加所有实体 [重复]的主要内容,如果未能解决你的问题,请参考以下文章
EF Core 5.0 - 更改“定义查询”映射实体时是不是需要生成迁移?