У меня есть следующие две сущности с их отображениями:
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();
}
}
У меня есть 2 модульных теста:
[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_
Если я изменяю сопоставление и изменяю Cascade.AllDeleteOrphan в VideoCategoryMap, второй тест завершается успешно, тогда как первый не проходит, поскольку потерянная папка видео не удаляется.
Как сделать оба теста успешными?
Заранее спасибо
Майк