使用子集合NHibernate自动化对象

时间:2012-11-21 20:21:52

标签: asp.net-mvc nhibernate fluent-nhibernate automapper

我刚刚从EF5切换到NHibernate,因为我想在ORM中使用一些功能,但在EF中找不到。所以,我是NHibernate的新手。我在ASP.Net MVC工作。

我正在使用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");
    }
}

这是我的View Model或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. 列出项目
    • ChildMenus集合应该有0个子对象,并且它没有子对象。
  4. 这是代码:

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

    有关此问题的任何想法,还是我需要将其置于另一个问题?谢谢!

1 个答案:

答案 0 :(得分: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");
    }
}

注意:

  • 架构应按约定或配置对象
  • 中的默认架构/目录定义
  • 从映射中删除所有不必要的声明,因为它经常引入可移植性问题(例如,customsqltypes),使代码复杂化并阻止约定
  • customsqltype()渲染长度()无用
  • 实际上并不需要Sortorder,因为列表已经定义了订单
  • parentId与Parent.Id重复,可在需要时实施ParentId { get { return ParentMenu == null ? null : (int?)ParentMenu.Id } },无需在字段中映射或存储

  • 如果不需要父引用,请从集合映射中删除它并.Inverse()