1

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

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

在存储库构造函数中,它为所有查询创建 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; }
 }

我只希望数据库存储每个标签的一个实例。如此多的文章可以使用相同的标签。所以我写了这个测试:

    [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”。

我相信它是因为会话仍然开放,所以休眠仍然保留所有内容并记住曾经发生过的事情。

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

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

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()))
4

1 回答 1

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#" });

对会话进行微观管理(刷新)也会降低性能。您的测试方法已经进行了9 - 13次分贝调用(取决于延迟加载设置)。

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

于 2012-11-05T08:30:11.793 回答