是否可以在 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>() 可以处理视图模型的扁平化或所需的层次结构。