我正在建立一个“了解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()))
答案 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}},以便可以正确批量插入/更新/删除。