[英]Fluent NHibernate many-to-many mapping saves all items but doesn't get all items
I have a Course table: 我有一个课程表:
CourseID Name
--------------------
1 Course 1
2 Course 2
3 Course 3
A Quiz table: 测验表:
QuizID CourseID Name
----------------------------
1 1 Quiz 1
2 1 Quiz 2
3 1 Quiz 3
A Question table: 问题表:
QuestionID Text
-----------------------------
1 What is foo?
2 What is bar?
3 What is foobar?
And a QuizQuestion table: 还有一个QuizQuestion表:
QuizID QuestionID
--------------------
1 1
1 2
2 2
2 3
The front-end for managing this data looks like this (I wish I had more say in how it has to look): 用于管理这些数据的前端如下所示(我希望我对它的外观有更多的发言权):
The UI probably doesn't matter, but hopefully it gives you a better idea. 用户界面可能并不重要,但希望它能给您一个更好的主意。 I'm using Fluent NHibernate with the following mappings: 我正在使用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();
}
}
Yes, the Quiz table maps to the Exam class for some reason. 是的,由于某种原因,测验表映射到Exam类。 When the form is posted, I look at each checkbox, determine whether the QuizQuestion already exists, and insert a new row if it doesn't. 发布表单后,我查看每个复选框,确定QuizQuestion是否已存在,如果不存在,则插入新行。 This part is working correctly, but here is the code anyways: 这部分工作正常,但是无论如何这是代码:
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 );
}
Say, for instance, I select the following checkboxes: 举例来说,我选择了以下复选框:
After I post the form, I can verify the new row was added by looking at the QuizQuestion table in the database: 发布表单后,可以通过查看数据库中的QuizQuestion表来验证是否添加了新行:
QuizID QuestionID
--------------------
1 1
1 2
2 2
2 3
3 1
3 3
For some reason, however, the new row is not part of the data set that is displayed on the following page. 但是,由于某种原因,新行不属于下一页显示的数据集。 After a save/commit/flush/redirect, the next page looks exactly like it did before: 保存/提交/刷新/重定向后,下一页看起来与之前完全一样:
It's not a problem with the view, because when I pause the debugger inside of the foreach loop in the GetQuestionModel method (below), exam.Questions
is empty: 视图不是问题,因为当我在下面的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;
}
Here's the GetAll method from the Repository class: 这是Repository类中的GetAll方法:
public virtual IQueryable<T> GetAll()
{
return LinqExtensionMethods.Query<T>( this.Session );
}
The strangest part of this whole thing is if I rebuild the solution the problem fixes itself. 整个过程中最奇怪的部分是,如果我重新构建解决方案,问题将自行解决。 It has to be a rebuild though, or a code change followed by a build. 但是它必须是重新构建,或者是代码更改,然后是构建。
This is driving me bonkers. 这使我疯狂。 What am I doing wrong? 我究竟做错了什么?
I suspected this had something to do with NHibernate caching, so I applied this mapping convention . 我怀疑这与NHibernate缓存有关,因此我应用了此映射约定 。 No luck however. 但是没有运气。
As I said earlier, a rebuild somehow refreshes the data. 如前所述,重建可以以某种方式刷新数据。 I was able to add several questions to Quiz with ID of 3, and after rebuilding they appeared in the list. 我能够向ID为3的测验中添加几个问题,并在重建后将其显示在列表中。 Then I deleted all the rows in the join table, but the questions are still in the list. 然后,我删除了联接表中的所有行,但问题仍在列表中。 I'm even more convinced now that this might be a problem with NHibernate caching. 现在,我更加确信这可能是NHibernate缓存的问题。
I finally found the problem: 我终于找到了问题:
var questions = QuestionRepository.GetAll()
.Select( q => GetQuestionModel( course.Exams, q ) )
.ToList();
Should be: 应该:
var questions = QuestionRepository.GetAll()
.ToList()
.Select( q => GetQuestionModel( course.Exams, q ) )
.ToList();
It seems like every time I have a frustratingly difficult problem with NHibernate it's because I'm missing a call to ToList somewhere. 似乎每次我在NHibernate中遇到一个令人沮丧的难题时,都是因为我在某个地方缺少对ToList的调用 。 It's starting to really get on my nerves. 它开始真的让我感到不安。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.