3

ORM に必要ないくつかの機能があり、EF では見つからなかったため、最近 EF5 から NHibernate に切り替えました。だから、私は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 コレクションには、実際の関連する子だけでなく、関連する子オブジェクトを含む、データベース内のすべての子オブジェクトの null オブジェクトが含まれます。オブジェクト。

例えば:

  1. ルートメニュー
    • ChildMenus コレクションには 3 つの子オブジェクトがあるはずですが、8 つ (5 つの null と 3 つの入力済み) があります。
  2. リスト項目
    • ChildMenus コレクションには 1 つの子オブジェクトがあるはずですが、8 つ (7 つの null と 1 つの値が設定されています) あります。
  3. リスト項目
    • ChildMenus コレクションには 0 の子オブジェクトがあるはずですが、子オブジェクトはありません。

これはコードです:

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

これに関するアイデアはありますか、それとも別の質問に入れる必要がありますか? ありがとうございました!

4

1 に答える 1

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()はlength()を役に立たなくします
  • リストはすでに順序を定義しているため、Sortorderは実際には必要ありません
  • parentIdはParent.Idと重複しており、必要に応じて実装できますParentId { get { return ParentMenu == null ? null : (int?)ParentMenu.Id } }。マップしたり、フィールドに保存したりする必要はありません。

  • 親参照が不要な場合は、それを削除し.Inverse()てコレクションマッピングから削除します

于 2012-11-28T08:52:42.353 に答える