0

我有以下兩個實體,用自己的映射:許多一對多和級聯:與實體問題缺失

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 [email protected];@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 [email protected];@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 [email protected];@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 [email protected];@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,第二測試成功,而第一失敗,因爲孤立視頻文件夾不會被刪除。

如何使兩種測試都成功?

在此先感謝

邁克

+0

第二次單元測試的問題到底是什麼?兩個斷言中的哪一個失敗? – Aaronontheweb 2010-12-07 17:41:57

+0

在第二個測試中,這是第一個失敗的斷言。我正在更新問題 – Mike 2010-12-07 18:53:01

回答

2

「刪除孤兒」在NHibernate的並不意味着「刪除實體沒有任何其他家長」。它意味着「刪除關係時,也刪除引用的實體」。

NHibernate不處理你需要OOTB的情況。可能的解決方案包括域級邏輯,存儲庫級邏輯,事件監聽器和觸發器。