【问题标题】:Fluent NHibernate many-to-many mapping saves all items but doesn't get all itemsFluent NHibernate 多对多映射保存所有项目但不获取所有项目
【发布时间】:2014-09-10 22:32:23
【问题描述】:

我有一个课程表:

CourseID    Name
--------------------
1           Course 1
2           Course 2
3           Course 3

测验表:

QuizID    CourseID    Name
----------------------------
1         1           Quiz 1
2         1           Quiz 2
3         1           Quiz 3

问题表:

QuestionID    Text
-----------------------------
1             What is foo?
2             What is bar?
3             What is foobar?

还有一个 QuizQuestion 表:

QuizID    QuestionID
--------------------
1         1
1         2
2         2
2         3

管理这些数据的前端看起来像这样(我希望我对它的外观有更多的发言权):

UI 可能无关紧要,但希望它能给你一个更好的主意。我正在使用具有以下映射的 Fluent NHibernate:

public class CourseMapOverride : IAutoMappingOverride<Course>
{
    public void Override( AutoMapping<Course> mapping )
    {
        mapping.Table( "Course" );

        mapping.Id( x => x.Id ).Column( "CourseID" );

        mapping.HasMany( x => x.Exams )
               .KeyColumn( "CourseID" )
               .Cascade.All()
               .Inverse();
    }
}

public class ExamMapOverride : IAutoMappingOverride<Exam>
{
    public void Override( AutoMapping<Exam> mapping )
    {
        mapping.Table( "Quiz" );

        mapping.Id( x => x.Id ).Column( "QuizID" );

        mapping.References( x => x.Course ).Column( "CourseID" );

        mapping.HasManyToMany( x => x.Questions )
               .Table( "QuizQuestion" )
               .ParentKeyColumn( "QuizID" )
               .ChildKeyColumn( "QuestionID" )
               .Cascade.All();
    }
}

public class QuestionMapOverride : IAutoMappingOverride<Question>
{
    public void Override( AutoMapping<Question> mapping )
    {
        mapping.Table( "Question" );

        mapping.Id( x => x.Id ).Column( "QuestionID" );

        mapping.HasManyToMany( x => x.Exams )
               .Table( "QuizQuestion" )
               .ParentKeyColumn( "QuestionID" )
               .ChildKeyColumn( "QuizID" )
               .Cascade.All()
               .Inverse();
    }
}

是的,测验表出于某种原因映射到考试类。发布表单后,我查看每个复选框,确定 QuizQuestion 是否已存在,如果不存在则插入新行。这部分工作正常,但这里是代码:

public void UpdateCourse( EditCourseModel model )
{
    var course = CourseRepository.Get( model.CourseID );

    course.Name = model.Name;

    foreach ( var examQuestionModel in model.Questions
                                            .SelectMany( q => q.ExamQuestions )
                                            .Where( eq => eq.Selected ) )
    {
        UpdateExamQuestion( course, examQuestionModel );
    }
}

private void UpdateExamQuestion( Course course, ExamQuestionModel model )
{
    var exam = course.Exams.First( e => e.Id == model.ExamID );

    if ( exam.Questions.Any( q => q.Id == model.QuestionID ) )
    {
        // it already exists
        return;
    }

    var question = QuestionRepository.Get( model.QuestionID );

    exam.Questions.Add( question );

    question.Exams.Add( exam );
}

比如说,我选择了以下复选框:

发布表单后,我可以通过查看数据库中的 QuizQuestion 表来验证是否添加了新行:

QuizID    QuestionID
--------------------
1         1
1         2
2         2
2         3
3         1
3         3

但是,由于某种原因,新行不属于下一页上显示的数据集。保存/提交/刷新/重定向后,下一页看起来与之前完全一样:

视图没有问题,因为当我在 GetQuestionModel 方法(下)的 foreach 循环内暂停调试器时,exam.Questions 为空:

public CourseModel GetCourseModel( int courseID )
{
    var course = CourseRepository.Get( courseID );

    var questions = QuestionRepository.GetAll()
                                      .Select( q => GetQuestionModel( course.Exams, q ) )
                                      .ToList();

    return new CourseModel
               {
                   CourseID = course.ID,
                   Name = course.Name,
                   Questions = questions,
               };
}

public QuestionModel GetQuestionModel( IEnumerable<Exam> exams, Question question )
{
    var model = new QuestionModel
                    {
                        QuestionID = question.ID,
                        Text = question.Text,
                        ExamQuestions = new List<ExamQuestionModel>(),
                    };
    
    foreach ( var exam in exams )
    {
        // exam.Questions is empty when exam.ID is 3
        var examQuestionIDs = exam.Questions.Select( q => q.ID );
        
        model.ExamQuestions.Add( new ExamQuestionModel
                                     {
                                         ExamID = exam.ID,
                                         QuestionID = question.ID,
                                         Selected = examQuestionIDs.Contains( question.ID ),
                                     } );
    }
    
    return model;
}

这是来自 Repository 类的 GetAll 方法:

public virtual IQueryable<T> GetAll()
{
    return LinqExtensionMethods.Query<T>( this.Session );
}

整个事情中最奇怪的部分是,如果我重新构建解决方案,问题就会自行解决。不过,它必须是重新构建,或者在构建之后更改代码。

这让我发疯了。我做错了什么?

编辑

我怀疑这与 NHibernate 缓存有关,所以我申请了this mapping convention。但是运气不好。

编辑 2

正如我之前所说,重建会以某种方式刷新数据。我能够在 ID 为 3 的测验中添加几个问题,重建后它们出现在列表中。然后我删除了连接表中的所有行,但问题在列表中仍然。我现在更加确信这可能是 NHibernate 缓存的问题。

【问题讨论】:

    标签: c# sql asp.net-mvc nhibernate fluent-nhibernate


    【解决方案1】:

    我终于找到问题了:

    var questions = QuestionRepository.GetAll()
                                      .Select( q => GetQuestionModel( course.Exams, q ) )
                                      .ToList();
    

    应该是:

    var questions = QuestionRepository.GetAll()
                                      .ToList()
                                      .Select( q => GetQuestionModel( course.Exams, q ) )
                                      .ToList();
    

    似乎每次我遇到令人沮丧的 NHibernate 问题时,都是因为我在某处错过了对 ToList 的调用。真的开始让我紧张了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-29
      • 1970-01-01
      • 2012-02-24
      • 1970-01-01
      • 1970-01-01
      • 2011-03-02
      相关资源
      最近更新 更多