我正在编写一个简单的应用程序来学习新技术。我坚持为我的应用程序编写单元测试:
[Test]
public void LessonChangeSubjectShouldNotAffectFormerSubjectPersistence()
{
// given
Lesson ExampleLesson = TestDataFactory.CreateLesson();
Save(ExampleLesson);
Refresh(ref ExampleLesson);
Subject formerSubject = ExampleLesson.Subject;
// when
Subject subject = TestDataFactory.CreateSubject();
_subjectService.Save(subject);
ExampleLesson.ChangeSubject(subject);
Update(ExampleLesson);
_subjectService.Update(formerSubject);
Refresh(ref ExampleLesson);
formerSubject = _subjectService.Get(formerSubject.Id);
subject = _subjectService.Get(subject.Id);
// then
ExampleLesson.Subject.Should().Be(subject);
formerSubject.Should().NotBeNull();
formerSubject.Lessons.Should().NotContain(ExampleLesson);
Refresh(ref ExampleLesson);
_subjectService.Delete(formerSubject);
Refresh(ref ExampleLesson);
Delete(ExampleLesson);
}
此方案包括:
此方案成功,但在最后一行清除测试失败时出现错误
NHibernate.PropertyValueException:not-null属性引用null或transient值Register.Core.Model.Lesson.Subject
Lesson类中的Subject字段映射如下:
References(x => x.Subject)
.Cascade.SaveUpdate()
.Column("SubjectId")
.Fetch.Select()
.ForeignKey("FK_Lessons_Subjects")
.Index("IX_Subject")
.LazyLoad()
.Not.Nullable();
Subject类中的Lessons集合映射为:
HasMany(x => x.Lessons)
.Access.CamelCaseField(Prefix.Underscore)
.Cascade.All()
.Fetch.Select()
.ForeignKeyConstraintName("FK_Lessons_Subjects")
.Inverse()
.KeyColumn("SubjectId")
.Not.KeyNullable()
.LazyLoad();
当我交换
_subjectService.Delete(formerSubject);
与
Refresh(ref ExampleLesson);
Delete(ExampleLesson);
没有来自NHibernate和测试通过的抱怨。我好奇发生了什么,为什么订单很重要。如果有人能指出我解决问题的方法,我也将非常感激。提前谢谢。
答案 0 :(得分:0)
错误可能是由于别名问题造成的。这里有两个课程副本,一个可以通过formersubject访问,因为课程集合不受刷新的影响。
我建议建模:
主题不应该有一系列课程
您必须不必要地不经常刷新它而不使用它来保持模型有效。它会随着时间的推移而增加,并带来各种各样的问题。您将倾向于对其进行过滤/枚举/排序,这将是一个内存操作而不是数据库调用。
<强> do not abstract away the ORM 强>
为实际业务逻辑提供服务。 DataAccessObjects(DAO)是多余的,因为NHibernate的ISession已经是一个。用于单元测试的Sqlite内存数据库还具有测试查询以返回正确内容的优势。
示例代码
class Lesson : Entity
{
public virtual string Name { get; set; }
public virtual Subject Subject { get; set; }
public void ChangeSubject(Subject subject)
{
// do some checks
Subject = subject;
}
}
class Subject : Entity
{
public string Name { get; set; }
}
[Test]
public void LessonChangeSubjectShouldNotAffectFormerSubjectPersistence()
{
var session = GetInMemorySession();
// given
Lesson exampleLesson = new Lesson { Name = "Lesson1", Subject = new Subject { Name = "Subject1" } };
session.Save(exampleLesson.Subject); // because we havent set cascade.save
session.Save(exampleLesson);
var formerSubjectId = exampleLesson.Subject.Id;
// when
Subject subject = new Subject { Name = "Subject2" };
session.Save(subject);
exampleLesson.ChangeSubject(subject);
session.Flush(); // save all changes
session.Clear();
var formerSubject = session.Get<Subject>(formerSubjectId);
subject = session.Get<Subject>(subject.Id);
// then
exampleLesson.Subject.Should().Be(subject);
formerSubject.Should().NotBeNull();
// technically not needed because the inmemory database is gone after this test
session.Delete(formerSubject);
session.Delete(subject);
}