是否可以在 Entity Framework 中忽略相关实体的加载?
Is it possible to ignore related entities from loading in Entity Framework?
我正在使用 Entity Framework 从数据库加载实体 (DataLayer
)。此实体在其模型 class 中引用了另一个实体 (DataLayerStyle
) 作为列表 Styles
.
第二个实体也引用回原始实体 (DataLayer
)。因此,当我加载原始实体时,它会以递归方式加载到第二个实体 (DataLayerStyle
) 中。我不想在这个特定实例中这样做,因为从服务器传输到客户端的数据量太大,客户端加载时间太长。
在将所有原始实体加载到变量之前,我尝试使用 Select 仅 select 第二个实体 class 中的某些参数,但我收到错误消息:
Lambda expression used inside Include is not valid
这也不是真正理想的解决方案,因为每一层都有不同的风格class,所以当我尝试以这种方式使用Select时,我只限于最通用的样式版本 class.
var list = dbContext.DataLayer.Where(x => x.LayerGroupId == groupId)
.Include(x => x.Permissions)
.Include(x => x.LayerGroup)
.ThenInclude(x => x.DataManager)
.ThenInclude(x => x.Project)
.Include(x => x.Styles
.Select(x => new { x.Visible, x.ImageURL, x.DataLayerId, x.DataLayerStyleId, x.UserId }))
.OrderBy(x => x.Name).AsNoTracking().ToList();
我也尝试添加 AsNoTracking()
但这也没有帮助。
我正在寻找与 Include 相反的东西,例如 DoNotInclude
,但它似乎不存在。
public class DataLayer
{
#region Properties
public int DataLayerId { get; set; }
public virtual LayerGroup LayerGroup { get; set; }
public int LayerGroupId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime DateCreated { get; set; }
public string DataLayerType { get; set; }
public virtual DataLayerDocumentManager DocumentManager { get; set; }
public virtual List<DataFeature> DataFeatures { get; set; } = new List<DataFeature>();
public virtual List<DataItemSummary> DataItemSummaries { get; set; } = new List<DataItemSummary>();
public virtual List<DataField> DataFields { get; set; } = new List<DataField>();
public virtual List<DataLayerStyle> Styles { get; set; } = new List<DataLayerStyle>();
public virtual List<DataLayerPermission> Permissions { get; set; } = new List<DataLayerPermission>();
public virtual List<DataLayerTag> Tags { get; set; } = new List<DataLayerTag>();
public virtual List<DataLayerLogEntry> LogEntries { get; set; } = new List<DataLayerLogEntry>();
public string UserId { get; set; }
#endregion
}
public class DataLayerStyle
{
#region Properties
public int DataLayerStyleId { get; set; }
public virtual DataLayer DataLayer { get; set; }
public int DataLayerId { get; set; }
public bool Visible { get; set; } = false;
public string UserId { get; set; }
public string ImageURL { get; set; }
#endregion
}
var list = dbContext.DataLayer.Where(x => x.LayerGroupId == groupId)
.Include(x => x.Permissions)
.Include(x => x.LayerGroup).ThenInclude(x => x.DataManager).ThenInclude(x => x.Project)
.Include(x => x.Styles)
.OrderBy(x => x.Name).AsNoTracking().ToList();
快速修复是禁用该查询的延迟加载。即:
using (var dbContext = new AppDbContext())
{
dbContext.Configuration.LazyLoadingEnabled = false;
// dbContext.ChangeTracker.LazyLoadingEnabled = false; // For EF Core.
var list = dbContext.DataLayer.Where(x => x.LayerGroupId == groupId)
.Include(x => x.Permissions)
.Include(x => x.LayerGroup)
.ThenInclude(x => x.DataManager)
.ThenInclude(x => x.Project)
.Include(x => x.Styles)
.OrderBy(x => x.Name).AsNoTracking().ToList();
// ...
}
如果 dbContext 是注入的 Context 或作用域在此调用之外:
dbContext.Configuration.LazyLoadingEnabled = false;
// dbContext.ChangeTracker.LazyLoadingEnabled = false; // For EF Core.
var list = dbContext.DataLayer.Where(x => x.LayerGroupId == groupId) // ...
dbContext.Configuration.LazyLoadingEnabled = true;
// dbContext.ChangeTracker.LazyLoadingEnabled = true; // For EF Core.
这将通过将未包含的引用(循环)保留为空来避免递归。
避免此类问题的更好解决方案是避免发送实体,而是定义要发送到视图的视图模型。这避免了担心急切加载或触发延迟加载的需要,并最大限度地减少了通过线路发送的数据。通常,视图不需要所有数据,并且可以将来自相关实体的大部分数据展平。 (即只需要 LayerGroupId 和 LayerGroupName 作为视图模型中的字段,DataLayerViewModel.LayerGroupName 与 DataLayer.LayerGroup.LayerGroupName)ViewModels 可以使用 .Select()
手动填充或作为 IQueryable
的一部分组成表达式 /w Automapper 的 ProjectTo<DataLayerViewModel>()
可以处理视图模型的扁平化或所需的层次结构。
我正在使用 Entity Framework 从数据库加载实体 (DataLayer
)。此实体在其模型 class 中引用了另一个实体 (DataLayerStyle
) 作为列表 Styles
.
第二个实体也引用回原始实体 (DataLayer
)。因此,当我加载原始实体时,它会以递归方式加载到第二个实体 (DataLayerStyle
) 中。我不想在这个特定实例中这样做,因为从服务器传输到客户端的数据量太大,客户端加载时间太长。
在将所有原始实体加载到变量之前,我尝试使用 Select 仅 select 第二个实体 class 中的某些参数,但我收到错误消息:
Lambda expression used inside Include is not valid
这也不是真正理想的解决方案,因为每一层都有不同的风格class,所以当我尝试以这种方式使用Select时,我只限于最通用的样式版本 class.
var list = dbContext.DataLayer.Where(x => x.LayerGroupId == groupId)
.Include(x => x.Permissions)
.Include(x => x.LayerGroup)
.ThenInclude(x => x.DataManager)
.ThenInclude(x => x.Project)
.Include(x => x.Styles
.Select(x => new { x.Visible, x.ImageURL, x.DataLayerId, x.DataLayerStyleId, x.UserId }))
.OrderBy(x => x.Name).AsNoTracking().ToList();
我也尝试添加 AsNoTracking()
但这也没有帮助。
我正在寻找与 Include 相反的东西,例如 DoNotInclude
,但它似乎不存在。
public class DataLayer
{
#region Properties
public int DataLayerId { get; set; }
public virtual LayerGroup LayerGroup { get; set; }
public int LayerGroupId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime DateCreated { get; set; }
public string DataLayerType { get; set; }
public virtual DataLayerDocumentManager DocumentManager { get; set; }
public virtual List<DataFeature> DataFeatures { get; set; } = new List<DataFeature>();
public virtual List<DataItemSummary> DataItemSummaries { get; set; } = new List<DataItemSummary>();
public virtual List<DataField> DataFields { get; set; } = new List<DataField>();
public virtual List<DataLayerStyle> Styles { get; set; } = new List<DataLayerStyle>();
public virtual List<DataLayerPermission> Permissions { get; set; } = new List<DataLayerPermission>();
public virtual List<DataLayerTag> Tags { get; set; } = new List<DataLayerTag>();
public virtual List<DataLayerLogEntry> LogEntries { get; set; } = new List<DataLayerLogEntry>();
public string UserId { get; set; }
#endregion
}
public class DataLayerStyle
{
#region Properties
public int DataLayerStyleId { get; set; }
public virtual DataLayer DataLayer { get; set; }
public int DataLayerId { get; set; }
public bool Visible { get; set; } = false;
public string UserId { get; set; }
public string ImageURL { get; set; }
#endregion
}
var list = dbContext.DataLayer.Where(x => x.LayerGroupId == groupId)
.Include(x => x.Permissions)
.Include(x => x.LayerGroup).ThenInclude(x => x.DataManager).ThenInclude(x => x.Project)
.Include(x => x.Styles)
.OrderBy(x => x.Name).AsNoTracking().ToList();
快速修复是禁用该查询的延迟加载。即:
using (var dbContext = new AppDbContext())
{
dbContext.Configuration.LazyLoadingEnabled = false;
// dbContext.ChangeTracker.LazyLoadingEnabled = false; // For EF Core.
var list = dbContext.DataLayer.Where(x => x.LayerGroupId == groupId)
.Include(x => x.Permissions)
.Include(x => x.LayerGroup)
.ThenInclude(x => x.DataManager)
.ThenInclude(x => x.Project)
.Include(x => x.Styles)
.OrderBy(x => x.Name).AsNoTracking().ToList();
// ...
}
如果 dbContext 是注入的 Context 或作用域在此调用之外:
dbContext.Configuration.LazyLoadingEnabled = false;
// dbContext.ChangeTracker.LazyLoadingEnabled = false; // For EF Core.
var list = dbContext.DataLayer.Where(x => x.LayerGroupId == groupId) // ...
dbContext.Configuration.LazyLoadingEnabled = true;
// dbContext.ChangeTracker.LazyLoadingEnabled = true; // For EF Core.
这将通过将未包含的引用(循环)保留为空来避免递归。
避免此类问题的更好解决方案是避免发送实体,而是定义要发送到视图的视图模型。这避免了担心急切加载或触发延迟加载的需要,并最大限度地减少了通过线路发送的数据。通常,视图不需要所有数据,并且可以将来自相关实体的大部分数据展平。 (即只需要 LayerGroupId 和 LayerGroupName 作为视图模型中的字段,DataLayerViewModel.LayerGroupName 与 DataLayer.LayerGroup.LayerGroupName)ViewModels 可以使用 .Select()
手动填充或作为 IQueryable
的一部分组成表达式 /w Automapper 的 ProjectTo<DataLayerViewModel>()
可以处理视图模型的扁平化或所需的层次结构。