【问题标题】:Entity Framework - Include Multiple Levels of Properties with different subclasses实体框架 - 包括具有不同子类的多级属性
【发布时间】:2016-06-05 18:10:59
【问题描述】:

我正在努力解决来自Entity Framework - Include Multiple Levels of Properties的问题

鉴于这些类:

class Survey {
    public virtual List<QuestionBase> Questions {get;set;}
    ...
}

class QuestionType1 : QuestionBase {
    public List<Answers> Answers {get;set;}
    ...
}
class QuestionType2 : QuestionBase {
    ...
}

我正在尝试获取用于深度克隆的实例,但无法使用以下方法获取答案:

Survey originalEntity = DBSet
            .Include(s => s.Questions)
            .Include(s => s.Questions.OfType<QuestionType1>().Select(q => q.Answers))
            .AsNoTracking()
            .Single( e => e.Id == sourceId );

使用这个我得到错误'包含路径表达式必须引用在类型上定义的导航属性。对引用导航属性使用虚线路径,对集合导航属性使用 Select 运算符。 参数名称:路径'

【问题讨论】:

  • Answers 是否定义在 QuestionBaseSimpleQuestion 中?
  • 它在 QuestionType1 中
  • 所以您想选择一个调查,并为特定问题类型加载特定答案?
  • 我想要 1 份调查问卷并加载所有问题。对于 QuestionType1 类型的问题,我希望加载所有答案
  • 如果最终结果是您试图克隆一个对象,我可以建议将其序列化为 string/xml/binary 然后再返回吗?

标签: c# entity-framework linq


【解决方案1】:

好的,所以这比我想象的花费了我更长的时间,但我想出了一个解决方案。但是,请注意,这不是“完整的 LINQ”解决方案,您需要一个 DB-Context 实例。我希望这可以满足您的需求。该解决方案的关键部分是为QuestionType1 的每个实例显式加载Answers 集合。

Survey survey;
int sourceId = 1;

using (var context = new YourDbContext())
{
  survey = context.Surveys.Include(s => s.Questions).Single(s => s.Id == sourceId);
  var questions = survey.Questions.OfType<QuestionType1>();
  foreach (var question in questions)
  {
    context.Entry(question).Collection(q => q.Answers).Load();
  }
}

/* just for testing to check if Questions and Answers are correctly loaded... */
Console.WriteLine(survey);
foreach (var questionBase in survey.Questions)
{
  Console.WriteLine("Question id " + questionBase.Id);
  var questionType1 = questionBase as QuestionType1;
  if (questionType1 != null)
  {
    foreach (var answer in questionType1.Answers)
    {
      Console.WriteLine("Answer " + answer.Id);
    }
  }
}

备注:

对于一个非常不常见的用例,这是一个非常不常见的解决方案。您可能需要重新考虑您是否真的需要这种行为,或者您是否可以提出更常见和更简单的解决方案。

【讨论】:

  • 这将产生编译错误:无法将类型 QuestionType1 隐式转换为 Survey
  • 感谢您的努力。但是,当我使用此代码时,我收到另一个错误:无法为属性“答案”调用成员“加载”,因为上下文中不存在“问题类型 1”类型的实体。要将实体添加到上下文中,请调用 DbSet 的 Add 或 Attach 方法。我必须对此进行更多研究,也许使用不同的方法
  • 由于错误状态,您需要添加一个属性 IDbSet { get;放; } 到您的上下文中以使这项工作。
  • ... 和 IDbSet { get;放; } 吗?
【解决方案2】:

为了帮助遇到同样问题的其他人,我将在此处发布我的解决方案:

Survey cloneSurvey = Context.Surveys
            .Include( s => s.Questions )
            .AsNoTracking()
            .FirstOrDefault( e => e.Id == sourceId );
        Context.Surveys.Add( cloneSurvey );

        IEnumerable<QuestionType1> questions = cloneSurvey.Questions.OfType<QuestionType1>();
        foreach( QuestionType1question in questions )
        {
            IEnumerable<Answer> answers = Context.Answers.AsNoTracking().Where( a => a.Question.Id == question.Id );
            foreach( Answer answer in answers )
            {
                Context.Set<Answer>().Add( answer );
                question.Answers.Add( answer );

            }
        }
        Context.SaveChanges();

尝试了很多解决方案,最后我遍历了问题和答案,将每个答案添加到 Context.Set

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-02
    • 1970-01-01
    • 2018-07-23
    • 1970-01-01
    相关资源
    最近更新 更多