使用NHibernate

时间:2017-11-24 14:01:39

标签: c# nhibernate fluent-nhibernate nunit

我正在编写一个简单的应用程序来学习新技术。我坚持为我的应用程序编写单元测试:

    [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);
    }

此方案包括:

  1. 使用默认随机主题创建课程并保存
  2. 创建新主题并根据新主题更改课程
  3. 检查旧主题是否仍然存在
  4. 此方案成功,但在最后一行清除测试失败时出现错误

      

    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和测试通过的抱怨。我好奇发生了什么,为什么订单很重要。如果有人能指出我解决问题的方法,我也将非常感激。提前谢谢。

1 个答案:

答案 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);
}