【问题标题】:Reference navigation property not loading (Entity Framework)参考导航属性未加载(实体框架)
【发布时间】:2022-01-16 04:02:21
【问题描述】:

我有 3 个模型:Human、Skill 和 HumanSkill。 Human 和Skill 之间存在多对多关系,HumanSkill 是它们之间的中间表。

我对数据库的查询正确加载了中间表HumanSkill 的集合,但没有加载引用导航属性Skill,我想通过该属性使用查询加载Skill 名称(Human -> HumanSkill -> Skill -> Skill.name)选择投影。

public IActionResult Preview(int humanId)
{
    var currentHuman = this.db.Humans
                              .Where(x => x.Id == humanId)
                              .Select(r => new HumanPreviewViewModel
                                      {
                                          PrimaryData = r.PrimaryData,
                                          // How should I write this line?
                                          Skills = r.Skills.ToList(), 
                                      }).SingleOrDefault();

    return View(currentResume);
}

人体模型:

public class Human
{
    public Human()
    {
        this.Skills = new HashSet<HumanSkill>();
    }

    public int Id { get; set; }

    public virtual PrimaryData PrimaryData { get; set; }
    public virtual ICollection<HumanSkill> Skills { get; set; }
}

HumanSkill模特:

public class HumanSkill
{
    public int Id { get; set; }

    public int HumanId { get; set; }
    public Human Human { get; set; }

    public int SkillId { get; set; }
    public Skill Skill { get; set; }
}

技能模型:

public class Skill
{
    public Skill()
    {
        this.Humans = new HashSet<HumanSkill>();
    }

    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<HumanSkill> Humans { get; set; }
}

HumanPreviewViewModel:

public class HumanPreviewViewModel
    {
        public HumanPreviewViewModel()
        {
        }
        public PrimaryData PrimaryData { get; set; }

        public List<HumanSkill> Skills { get; set; }
    }
}

【问题讨论】:

  • 您可以在HumanSkill上查询,然后使用Include查询Skill
  • 如何在不使用包含的情况下实现这一目标?我更喜欢查询预测。
  • 在 Select 或 Where 中使用来自 Skill 的一些数据..

标签: c# asp.net entity-framework


【解决方案1】:

当从实体投影到视图模型时,避免混合它们。例如,不要让视图模型包含引用或实体集。虽然看起来没有必要,但如果您想在 HumanPreviewViewModel 中列出技能及其 ID 和名称,则为该技能创建一个可序列化的视图模型,如果这是另一个相关实体,则为 PrimaryData 创建一个可序列化视图模型。如果 PrimaryData 可能是一对一或多对一,则可以将此关系中的所需属性“展平”到视图模型中。

[Serializable]
public class HumanPreviewViewModel
{
    public Id { get; set; }
    public string DataPoint1 { get; set; }
    public string DataPoint2 { get; set; }

    public List<SkillViewModel> Skills { get; set; }
}

[Serializable]
public class SkillViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
}

那么当你去提取你的人类时:

var currentHuman = this.db.Humans
    .Where(x => x.Id == humanId)
    .Select(r => new HumanPreviewViewModel
    {
        Id = r.Id,
        DataPoint1 = r.PrimaryData.DataPoint1,
        DataPoint2 = r.PrimaryData.DataPoint2,
        Skills = r.Skills.Select(s => new SkillViewModel
        {
            Id = s.Skill.Id,
            Name = s.Skill.Name
        }).ToList()
    }).SingleOrDefault();

即使视图模型和实体共享所有所需字段,您也不要将它们混合在一起的原因是您的实体通常包含对更多实体的引用。当您的视图模型之类的东西被发送到序列化器时,例如从 API 发送到客户端,或者由于页面调用看起来很无辜的东西:

var model = @Html.Raw(Json.Encode(Model));

然后序列化程序可以并且将触摸您引用的实体中的导航属性,这将触发大量延迟加载调用。

【讨论】:

  • 感谢您向我提供这些信息。我是 ASP.NET 的新手,我会阅读更多关于这个主题的内容。
【解决方案2】:

如何在不使用包含的情况下实现这一点?

如果您在 Select 中使用 Skills 表中的一些数据,EF 将执行必要的连接来检索数据

  var currentHuman = this.db.Humans
      .Where(x => x.Id == humanId)
      .Select(r => new HumanPreviewViewModel
              {
                  PrimaryData = r.PrimaryData,
                  SkillNames = r.Skills.Select(hs => hs.Skill.Name).ToList(), 
              }).SingleOrDefault();

【讨论】:

  • 我想将技能名称加载到 ViewModel 中显示的 HumanSkill 列表中。我不希望单独创建技能名称列表。这可能吗?
  • 我的 psot 只是我提出的“访问选择中的数据”点的一个示例。您的 viewModel 不太有意义,因为它似乎不够深入;让您的 VM 引用数据库实体 HumanSkill 是不合逻辑的。你的虚拟机应该有一个List&lt;SkillViewModel&gt; ?
  • 我的HumanPreviewViewModel只有两个属性:PrimaryData PrimaryData和List&lt;HumanSkill&gt; Skills。
  • 这是有点令人困惑,因为HumanSkill 是一个数据库实体,而不是一个视图模型。您的视图模型应该只有简单的道具(字符串,int)或xxviewmodels(它们本身只有简单的道具或视图模型)......它应该有例如List&lt;HumanSkillViewModel&gt;
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多