EF6:将 DataGridView 的 DataSource 设置为 EF-Entity 也会导致加载其子项。为什么?
EF6: Setting DataGridView's DataSource to an EF-Entity results in loading its children as well. Why?
我正在努力使它尽可能简短:
我有一个包含一些表的简单数据库:
艺术家、专辑、歌曲。
- 艺术家可能有多张专辑。专辑可能是由多位艺术家(多对多)创建的。
- 一个专辑可以有多首歌曲,但一首歌曲仅限于一张专辑(一对多)。
EntityFramework把这些表放到类就好了。现在,我将 DbContext 实例绑定到 Windows Forms C# 项目中的 DataGridView:
DBEntities db = new DBEntities();
db.Artists.Include(a => a.Albums).Load(); // include children albums as well
artistBindingSource.DataSource = db.Artists.Local.ToBindingList();
DataGridView 实例正确显示内容。我可以保存修改之类的。
如果用户单击 DataGridView 中的单元格(带有艺术家姓名),我将通过将第二个 DataGridView(带有 albumBindingSource)分配给艺术家的专辑集合来加载相关专辑:
Artist a = (Artist)row.DataBoundItem; // row contains selected grid row
if (a != null)
{
albumBindingSource.DataSource = a.Albums;
}
这也可以,但是在调试 SQL 语句时我发现了一些奇怪的东西:
将第二个 DataGridView 的数据源分配给 a.albums(即所选实例的专辑)时,Entity Framework 还会在多个 SELECT 语句(每首歌曲一个)中延迟加载专辑的歌曲。
问题 1: 为什么还要加载相册的子项?我从来没有告诉它这样做。
但是:如果我将以下代码添加到预加载实体的行中,延迟加载就会消失:
db.Artists.Include(c => c.Albums.Select(b => b.Songs)).Load();
问题 2: 我真的需要预加载所有的子孙子代以防止延迟加载吗?我从来不希望孙子们出现在我的 Windows 表格中。
问题三:(见Q.2)为什么是"include"然后是"select"?我觉得像...
db.Artists.Include(c => c.Albums.Include(d => d.Songs)).Load();
...会更直观。
无论如何:感谢您在这里帮助我!
正在加载实体可能是因为 LazyLoading 已打开。您可以通过 db.Configuration.LazyLoadingEnabled = false;
关闭 LazyLoading,无需加载所有内容。此外,还有两个 Include
方法(不包括 overloads)。一个是DbQuery<TEntity>
的方法,DbSet<TEntity>
继承了它,所以你可以看到Include
方法为你的集合,另一个是QuerableExtensions
class中的方法,这是扩展方法IQuerable<T>
,在 System.Data.Entity
命名空间中。所以它是为 IQuerable
编写的,您使用 Select
方法指定子集合。
我正在努力使它尽可能简短:
我有一个包含一些表的简单数据库: 艺术家、专辑、歌曲。
- 艺术家可能有多张专辑。专辑可能是由多位艺术家(多对多)创建的。
- 一个专辑可以有多首歌曲,但一首歌曲仅限于一张专辑(一对多)。
EntityFramework把这些表放到类就好了。现在,我将 DbContext 实例绑定到 Windows Forms C# 项目中的 DataGridView:
DBEntities db = new DBEntities();
db.Artists.Include(a => a.Albums).Load(); // include children albums as well
artistBindingSource.DataSource = db.Artists.Local.ToBindingList();
DataGridView 实例正确显示内容。我可以保存修改之类的。
如果用户单击 DataGridView 中的单元格(带有艺术家姓名),我将通过将第二个 DataGridView(带有 albumBindingSource)分配给艺术家的专辑集合来加载相关专辑:
Artist a = (Artist)row.DataBoundItem; // row contains selected grid row
if (a != null)
{
albumBindingSource.DataSource = a.Albums;
}
这也可以,但是在调试 SQL 语句时我发现了一些奇怪的东西: 将第二个 DataGridView 的数据源分配给 a.albums(即所选实例的专辑)时,Entity Framework 还会在多个 SELECT 语句(每首歌曲一个)中延迟加载专辑的歌曲。
问题 1: 为什么还要加载相册的子项?我从来没有告诉它这样做。
但是:如果我将以下代码添加到预加载实体的行中,延迟加载就会消失:
db.Artists.Include(c => c.Albums.Select(b => b.Songs)).Load();
问题 2: 我真的需要预加载所有的子孙子代以防止延迟加载吗?我从来不希望孙子们出现在我的 Windows 表格中。
问题三:(见Q.2)为什么是"include"然后是"select"?我觉得像...
db.Artists.Include(c => c.Albums.Include(d => d.Songs)).Load();
...会更直观。
无论如何:感谢您在这里帮助我!
正在加载实体可能是因为 LazyLoading 已打开。您可以通过 db.Configuration.LazyLoadingEnabled = false;
关闭 LazyLoading,无需加载所有内容。此外,还有两个 Include
方法(不包括 overloads)。一个是DbQuery<TEntity>
的方法,DbSet<TEntity>
继承了它,所以你可以看到Include
方法为你的集合,另一个是QuerableExtensions
class中的方法,这是扩展方法IQuerable<T>
,在 System.Data.Entity
命名空间中。所以它是为 IQuerable
编写的,您使用 Select
方法指定子集合。