内存单元测试中的NHibernate SQLite与物理数据库的工作方式不同

时间:2012-11-01 13:58:29

标签: sqlite unit-testing fluent-nhibernate automapping

我正在建立一个“了解NHibernate项目”。

我的单元测试(nunit)为存储库层提供与普通mvc站点相同的配置,但使用“SQLiteConfiguration.Standard.InMemory()”而不是“MsSqlConfiguration.MsSql2008”。我的希望是我可以使用流畅的nhibernate和自动化完全相同的方式,但有一个快速的内存数据库用于测试和一个真正的应用程序数据库。

在存储库构造函数中,它为所有要使用的查询创建Session对象,并且还实现IDisposable,这将确保正确处理会话。例如,保存文章方法如下所示:

    public void SaveArticle(Article article)
    {            
        Session.SaveOrUpdate(article);      
        Session.Flush();
    }

到目前为止,MVC网站似乎都正常工作,我的测试正在通过。我想我遇到了一个问题,这个问题一定是我的设计问题。

到目前为止,我有两个对象:

class Article
{
    public virtual int Id {get; set; }
    public virtual IList<Tag> Tags {get; set; }
 }

 class Tag
 {
    public virtual int Id {get; set; }
    public virtual string Text {get; set; }
 }

我只希望DB存储每个标记的一个实例。这么多文章都可以使用相同的标签。所以我写了这个测试:

    [Test]
    public void TestDeletingTagWillNotDeleteOthersTagV2()
    {
        Article article = new Article();
        article.Tags.Add(new Tag { Text = "C#" });
        article.Tags.Add(new Tag { Text = "VB" });
        Service.SaveArticle(article);

        Article article2 = new Article();
        article2.Tags.Add(new Tag { Text = "C#" });
        Service.SaveArticle(article2);

        Guid article1Id = article.Id;
        Guid article2Id = article2.Id;

        article = null;
        article2 = null;

        Article article3 = Service.GetArticle(article1Id);
        Article article4 = Service.GetArticle(article2Id);

        Assert.AreEqual(2, article3.Tags.Count);
        Assert.AreEqual(1, article4.Tags.Count);

        Assert.AreEqual(2, Service.Tags.Count);

        article3.Tags.RemoveAt(0);
        Service.SaveArticle(article3);

        Article article5 = Service.GetArticle(article1Id);
        Article article6 = Service.GetArticle(article2Id);

        Assert.AreEqual(1, article5.Tags.Count);
        Assert.AreEqual(1, article6.Tags.Count);

        Assert.AreEqual(2, Service.Tags.Count);
    }

这个测试通过,但我相信它会失败。 (当你运行MVC网站时,即第一篇文章只有一个标签,“VB”不是“C#”和“VB”。

我相信它是因为当会话仍处于打开状态时,nhibernate仍然会抓住所有内容并记住它的内容。

我的主要问题是如何使用内存数据库进行测试?如何在保存和删除共享标签后确保文章仍然具有应有的功能?

它创建的表结构是(我觉得错误,应该有一个链接表):

Article:
    Id (PK, uniqueid, not null)
     ...........

 Tag
    Id (PK, uniqueid, not null)
    Text (nvarchar, null)
    Article_id (FK, uniqueid, null)

不确定如何使用流畅的自动化来设置链接表,以便一个标记可以跨多个文章共享,一个文章可以有多个标记

相信我找到了如何确保标签和文章有一个链接表:

        configuration.Mappings(m => m.AutoMappings.Add((AutoMap.AssemblyOf<Article>())
                            .Override<Article>(map => map.IgnoreProperty(x => x.IsPublished))
                            .Override<Article>(map => map.HasManyToMany(a => a.Tags).Cascade.All())
                            .Conventions.Add(DefaultCascade.All()))

1 个答案:

答案 0 :(得分:0)

如果您只想要唯一标记(文本是唯一的),则使文本唯一,并使用会话获取唯一实例。对于具有相同文本但不同ID的NHibernate标签是不同的。

// do
article.Tags.Add(session.Get<Tag>(cSharpId));
// or
article.Tags.Add(session.Query<Tag>().Where(t => t.Text == "C#"));
// instead of
article.Tags.Add(new Tag { Text = "C#" });

还会对会话进行微观管理(Flush)会降低性能。您的测试方法已经执行 9 - 13 db调用(取决于延迟加载设置)。

而不是服务方法中的Session.Flush();至少引入一个调用SaveChanges()的{​​{1}},以便可以正确批量插入/更新/删除。