2012-11-21 69 views
3

我剛剛從EF5切換到NHibernate,因爲我想在我的ORM中找到一些功能,但在EF中找不到它。所以,我是NHibernate的新手。我正在使用ASP.Net MVC。使用子集合自動映射對象NHibernate

我使用Automapper將FNH對象映射到我的視圖模型,但我遇到的問題以前是如何將EF做到FNH的。例如,我有一個自我參照表,它是一個菜單系統。

這裏是模型:

public partial class Menu { 

    private int _Id; 

    private string _Title; 

    private string _Link; 

    private int _SortOrder; 

    private System.Nullable<int> _ParentMenuId; 

    private Iesi.Collections.ISet _ChildMenus; 

    private Menu _ParentMenu; 

    #region Extensibility Method Definitions 

    partial void OnCreated(); 

    #endregion 

    public Menu() 
    { 
     this._ChildMenus = new Iesi.Collections.HashedSet(); 
     OnCreated(); 
    } 


    /// <summary> 
    /// There are no comments for Id in the schema. 
    /// </summary> 
    public virtual int Id 
    { 
     get 
     { 
      return this._Id; 
     } 
     set 
     { 
      this._Id = value; 
     } 
    } 


    /// <summary> 
    /// There are no comments for Title in the schema. 
    /// </summary> 
    public virtual string Title 
    { 
     get 
     { 
      return this._Title; 
     } 
     set 
     { 
      this._Title = value; 
     } 
    } 


    /// <summary> 
    /// There are no comments for Link in the schema. 
    /// </summary> 
    public virtual string Link 
    { 
     get 
     { 
      return this._Link; 
     } 
     set 
     { 
      this._Link = value; 
     } 
    } 


    /// <summary> 
    /// There are no comments for SortOrder in the schema. 
    /// </summary> 
    public virtual int SortOrder 
    { 
     get 
     { 
      return this._SortOrder; 
     } 
     set 
     { 
      this._SortOrder = value; 
     } 
    } 


    /// <summary> 
    /// There are no comments for ParentMenuId in the schema. 
    /// </summary> 
    public virtual System.Nullable<int> ParentMenuId 
    { 
     get 
     { 
      return this._ParentMenuId; 
     } 
     set 
     { 
      this._ParentMenuId = value; 
     } 
    } 


    /// <summary> 
    /// There are no comments for ChildMenus in the schema. 
    /// </summary> 
    public virtual Iesi.Collections.ISet ChildMenus 
    { 
     get 
     { 
      return this._ChildMenus; 
     } 
     set 
     { 
      this._ChildMenus = value; 
     } 
    } 


    /// <summary> 
    /// There are no comments for ParentMenu in the schema. 
    /// </summary> 
    public virtual Menu ParentMenu 
    { 
     get 
     { 
      return this._ParentMenu; 
     } 
     set 
     { 
      this._ParentMenu = value; 
     } 
    } 
} 

這裏是映射:

public class MenuMap : ClassMap<Menu> 
{ 
    public MenuMap() 
    { 
      Schema(@"dbo"); 
      Table(@"Menus"); 
      LazyLoad(); 
      Id(x => x.Id) 
      .Column("Id") 
      .CustomType("Int32") 
      .Access.Property() 
      .CustomSqlType("int") 
      .Not.Nullable() 
      .Precision(10)     
      .GeneratedBy.Identity(); 
      Map(x => x.Title)  
      .Column("Title") 
      .CustomType("String") 
      .Access.Property() 
      .Generated.Never() 
      .CustomSqlType("varchar"); 
      Map(x => x.Link)  
      .Column("Link") 
      .CustomType("String") 
      .Access.Property() 
      .Generated.Never() 
      .CustomSqlType("varchar") 
      .Not.Nullable() 
      .Length(50); 
      Map(x => x.SortOrder)  
      .Column("SortOrder") 
      .CustomType("Int32") 
      .Access.Property() 
      .Generated.Never() 
      .Not.Nullable() 
      .UniqueKey("KEY1"); 
      Map(x => x.ParentMenuId)  
      .Column("ParentMenuId") 
      .CustomType("Int32") 
      .Access.Property() 
      .Generated.Never() 
      .UniqueKey("KEY1"); 
      HasMany<Menu>(x => x.ChildMenus) 
      .Access.Property() 
      .AsSet() 
      .Cascade.None() 
      .LazyLoad() 
      .Inverse() 
      .Not.Generic() 
      .KeyColumns.Add("ParentMenuId", mapping => mapping.Name("ParentMenuId") 
                   .SqlType("int") 
                   .Nullable()); 
      References(x => x.ParentMenu) 
      .Class<Menu>() 
      .Access.Property() 
      .Cascade.None() 
      .LazyLoad() 
      .Columns("ParentMenuId"); 
    } 
} 

這裏是我的視圖模型或DTO:

public class MainMenuItemViewModel 
{ 
    public Int32 Id { get; set; } 
    public string Title { get; set; } 
    public string Link { get; set; } 
    public Int32 SortOrder { get; set; } 
    public Int32? ParentMenuId { get; set; } 
    public IList<MainMenuItemViewModel> ChildMenus { get; set; } 
} 

當我試圖映射域對象視圖模型,使用此:

Mapper.CreateMap<Menu, MainMenuItemViewModel>(); 

我碰到下面的錯誤在我檢查配置上運行有效:

The following property on WinStream.WebUI.Models.MainMenuItemViewModel cannot be mapped: ChildMenus 
Add a custom mapping expression, ignore, add a custom resolver, or modify the destination type WinStream.WebUI.Models.MainMenuItemViewModel. 
Context: 
    Mapping to property ChildMenus from System.Object to WinStream.WebUI.Models.MainMenuItemViewModel 
    Mapping to property ChildMenus from Iesi.Collections.ISet to System.Collections.Generic.IList`1[[WinStream.WebUI.Models.MainMenuItemViewModel, WinStream.WebUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] 
    Mapping from type WinStream.Services.Entities.Menu to WinStream.WebUI.Models.MainMenuItemViewModel 
Exception of type 'AutoMapper.AutoMapperConfigurationException' was thrown. 

我想這可能涉及到的ISet轉換爲IList的,所以我把在ISet的在我的視圖模型,但仍然有問題。

感謝您的幫助 - 我意識到這可能是一個完整的新手問題,但我無法通過Google找到太多幫助。我一直在爲此奮鬥了好幾天。

謝謝!

編輯:

我過得了上述錯誤,但現在當我查詢數據庫中,ChildMenus集合根對象包括在數據庫中爲每一個孩子對象空對象,包括關聯的子對象,而不僅僅是實際相關的子對象。

例如:

  1. 根菜單
    • ChildMenus集合應該有3個對象,但有8個(5空和3填充)
  2. 列表項
    • ChildMenus集合應該有1個子對象,但它有8個(7個空值和1個填充)
  3. List item
    • ChildMenus集合應該有0個子對象,並且它沒有子對象。

這是代碼:

IList<Menu> menus = session.Query<Menu>().Where(x => x.ParentMenuId== null).ToList() 

對此有何想法,或者我需要把它變成了另一個問題?謝謝!

+1

您是否嘗試將'Menu.ChildMenus'類型從'Iesi.Collections.ISet'更改爲'列表

'? – Suhas

+0

是的,我仍然收到相同的錯誤消息,只是將Iesi.Collections.Iset更改爲錯誤消息中的List。 – Drewsonian

+1

而且......我仔細檢查了一下,發現我使用了System.Collections.IList和System.Collections.Generic.IList。所以我只是將.Generic()添加到流暢映射中並且它可以工作。 – Drewsonian

回答

2

NHibernate不需要很多來自EF的解決方法。你基本上有一個菜單與有序的孩子有父母的參考。

public class Menu 
{ 
    public int Id { get; protected set; } 

    public string Title { get; set; } 
    public string Link { get; set; } 

    public IList<Menu> ChildMenus { get; protected set; } 
    public Menu ParentMenu { get; set; } 

    public Menu() 
    { 
     ChildMenus = new List<Menu>(); 
    } 
} 

public class MenuMap : ClassMap<Menu> 
{ 
    public MenuMap() 
    { 
      Table(@"Menus"); 
      Id(x => x.Id).GeneratedBy.Identity(); 
      Map(x => x.Title).Length(100); 
      Map(x => x.Link).Length(50); 
      HasMany<Menu>(x => x.ChildMenus) 
       .AsList("SortOrder") 
       .Inverse() 
       .KeyColumn("ParentMenuId"); 
      References(x => x.ParentMenu).Column("ParentMenuId"); 
    } 
} 

注:

  • 模式應當按照慣例或作爲配置對象
  • 刪除從映射所有unnessesary聲明默認架構/目錄,因爲它常常引入可移植性問題定義(例如。 ()),使代碼複雜化並阻止約定
  • customsqltype()呈現長度()無用
  • Sortorder並不是真的需要導致列表已經定義的順序
  • parentId的是重複的Parent.Id並可以根據需要ParentId { get { return ParentMenu == null ? null : (int?)ParentMenu.Id } }來實現,無需地圖或將其存儲在現場

  • 如果不需要parentreference刪除和.Inverse()從集合映射