我有以下两个实体及其映射:
public class VideoCategory : BaseEntity<VideoCategory>
{
private readonly Iesi.Collections.Generic.ISet<VideoFolder> folders = new HashedSet<VideoFolder>();
public VideoCategory()
{
}
public VideoCategory(string name)
{
Name = name;
}
public string Name { get; set; }
public IEnumerable<VideoFolder> Folders { get { return folders; } }
public void AddFolder(VideoFolder videoFolder)
{
Contract.Requires(videoFolder != null);
if (folders.Contains(videoFolder))
return;
folders.Add(videoFolder);
videoFolder.AddCategory(this);
}
public void RemoveFolder(VideoFolder videoFolder)
{
folders.Remove(videoFolder);
videoFolder.RemoveCategory(this);
}
public void ClearFolders()
{
folders.ForEach(f => f.RemoveCategory(this));
folders.Clear();
}
}
public class VideoFolder : BaseEntity<VideoFolder>
{
private readonly Iesi.Collections.Generic.ISet<VideoCategory> categories = new HashedSet<VideoCategory>();
public VideoFolder()
{
}
public VideoFolder(string path)
{
Path = path;
}
public string Path { get; set; }
public string Name { get; private set; }
public IEnumerable<VideoCategory> Categories { get { return categories; } }
protected internal void AddCategory(VideoCategory videoCategory)
{
Contract.Requires(videoCategory != null);
categories.Add(videoCategory);
}
protected internal void RemoveCategory(VideoCategory videoCategory)
{
categories.Remove(videoCategory);
}
}
public class VideoCategoryMap : ClassMap<VideoCategory>
{
public VideoCategoryMap()
{
Table("VideoCategories");
Id(cat => cat.Id)
.GeneratedBy.Native();
Map(cat => cat.Name)
.Unique()
.Not.Nullable();
HasManyToMany<VideoFolder>(Reveal.Member<VideoCategory>("folders"))
.Access.CamelCaseField()
.AsSet()
.Inverse()
.Cascade.AllDeleteOrphan();
}
}
public class VideoFolderMap : ClassMap<VideoFolder>
{
public VideoFolderMap()
{
Table("VideoFolders");
Id(folder => folder.Id)
.GeneratedBy.Native();
Map(folder => folder.Path)
.Not.Nullable();
HasManyToMany<VideoCategory>(Reveal.Member<VideoFolder>("categories"))
.Access.CamelCaseField()
.AsSet();
}
}
我有这两个单元测试:
[Fact]
public void DeletingVideocategory_DeletesVideoFolders()
{
object id;
using (ISession session = SessionFactory.OpenSession())
{
var categ = new VideoCategory("Foo");
var folder = new VideoFolder("D:\\Foo");
categ.AddFolder(folder);
id = session.Save(categ);
session.Flush();
}
using (ISession session = SessionFactory.OpenSession())
{
var category = session.Get<VideoCategory>(id);
category.ClearFolders();
session.Delete(category);
session.Flush();
Assert.Equal(0, session.QueryOver<VideoFolder>().RowCount());
}
}
[Fact]
public void DeletingVideocategory_DoesntDeleteVideoFoldersOwned_ByOtherCategories()
{
object id;
object id2;
using (ISession session = SessionFactory.OpenSession())
{
var categ = new VideoCategory("Foo");
var categ2 = new VideoCategory("Bar");
var folder = new VideoFolder("D:\\Foo");
categ.AddFolder(folder);
categ2.AddFolder(folder);
id = session.Save(categ);
id2 = session.Save(categ2);
session.Flush();
}
using (ISession session = SessionFactory.OpenSession())
{
var category = session.Get<VideoCategory>(id);
category.ClearFolders();
session.Delete(category);
session.Flush();
Assert.Equal(1, session.QueryOver<VideoFolder>().RowCount());
Assert.Equal(1, session.Get<VideoCategory>(id2).Folders.Count());
}
}
第一个成功,但不是第二个的第一个断言,其中视频文件夹被删除,而它仍然与剩余的视频类别相关联。
这是第二个测试的SQL输出:
INSERT INTO VideoCategories (Name) VALUES (@p0); select last_insert_rowid();@p0 = 'Foo' [Type: String (0)]
INSERT INTO VideoFolders (Path) VALUES (@p0); select last_insert_rowid();@p0 = 'D:\Foo' [Type: String (0)]
INSERT INTO VideoCategories (Name) VALUES (@p0); select last_insert_rowid();@p0 = 'Bar' [Type: String (0)]
INSERT INTO CategoriesToFolders (VideoFolder_id, VideoCategory_id) VALUES (@p0, @p1);@p0 = 1 [Type: Int32 (0)], @p1 = 1 [Type: Int32 (0)]
INSERT INTO CategoriesToFolders (VideoFolder_id, VideoCategory_id) VALUES (@p0, @p1);@p0 = 1 [Type: Int32 (0)], @p1 = 2 [Type: Int32 (0)]
SELECT videocateg0_.Id as Id10_0_, videocateg0_.Name as Name10_0_ FROM VideoCategories videocateg0_ WHERE videocateg0_.Id=@p0;@p0 = 1 [Type: Int32 (0)]
SELECT folders0_.VideoCategory_id as VideoCat1_1_, folders0_.VideoFolder_id as VideoFol2_1_, videofolde1_.Id as Id13_0_, videofolde1_.Path as Path13_0_ FROM CategoriesToFolders folders0_ left outer join VideoFolders videofolde1_ on folders0_.VideoFolder_id=videofolde1_.Id WHERE folders0_.VideoCategory_id=@p0;@p0 = 1 [Type: Int32 (0)]
SELECT categories0_.VideoFolder_id as VideoFol2_1_, categories0_.VideoCategory_id as VideoCat1_1_, videocateg1_.Id as Id10_0_, videocateg1_.Name as Name10_0_ FROM CategoriesToFolders categories0_ left outer join VideoCategories videocateg1_ on categories0_.VideoCategory_id=videocateg1_.Id WHERE categories0_.VideoFolder_id=@p0;@p0 = 1 [Type: Int32 (0)]
SELECT videos0_.VideoFolder_id as VideoFol3_1_, videos0_.Id as Id1_, videos0_.Id as Id12_0_, videos0_.Path as Path12_0_ FROM VideoFiles videos0_ WHERE videos0_.VideoFolder_id=@p0;@p0 = 1 [Type: Int32 (0)]
DELETE FROM CategoriesToFolders WHERE VideoFolder_id = @p0;@p0 = 1 [Type: Int32 (0)]
DELETE FROM VideoFolders WHERE Id = @p0;@p0 = 1 [Type: Int32 (0)]
DELETE FROM VideoCategories WHERE Id = @p0;@p0 = 1 [Type: Int32 (0)]
SELECT count(*) as y0_ FROM VideoFolders this_
如果我更改了映射,并在VideoCategoryMap中修改了Cascade.AllDeleteOrphan,则第二次测试成功,而第一次测试失败,因为孤立的视频文件夹未被删除。
如何让这两项测试成功?
提前致谢
迈克答案 0 :(得分:2)
NHibernate不处理你需要OOTB的情况。可能的解决方案包括域级逻辑,存储库级逻辑,事件监听器和触发器。