2

我有一个 nHibernate 父子表关系。父类当前正在将子类拉入 List 但我想根据表中的排序列将它们放入 SortedList 中。如何更改 NHibernate 映射文件以让系统​​知道我正在订购哪一列?

当前的 NHibernate 映射文件是:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   namespace="Model.Configuration.Pages"
                   assembly="Model.Configuration">
  <joined-subclass
            table="PageConfigurations"
            name="PageConfiguration"
            extends="Model.Configuration.Configuration.TargetedConfiguration"
            lazy="false">
    <key column="TargetedConfigurationId" />

    <property name="SchemaVersion" />

    <property name="Template" type="System.String" length="50" />

    <property name="PageKey" type="System.String" length="50" />

    <property name="Percentage" />

    <bag name="Controls" cascade="all-delete-orphan" lazy="false" >
      <key column="PageConfigurationId" />
      <one-to-many class="WidgetConfiguration"/>
    </bag>

  </joined-subclass>
</hibernate-mapping>

对于父表和:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   namespace="Model.Configuration.Pages"
                   assembly="Model.Configuration">
  <class name="WidgetConfiguration" lazy="false" table="PageConfiguration_Widgets" discriminator-value="Default">
    <id name="Id"  unsaved-value="0" type="int" >
      <generator class="identity" />
    </id>
    <discriminator column="ConfigurationType" />

    <property name="Slot" type="System.String" length="100" />
    <property name="WidgetTypeName" type="System.String" length="100"/>
    <property name="ViewName" type="System.String" length="50" />
    <property name="SlotOrder" type="System.Int32" />
  </class>
</hibernate-mapping>

对于子表。

在将 WidgetConfiguration 提取到 SortedList 时,我需要向父映射或子映射添加什么以让他们知道新的 SlotOrder 列应用作关键字段。

编辑:数据被读入的类是:

public class PageConfiguration : TargetedConfiguration 
{

    public PageConfiguration()
    {
        // replaced by SortedList
        //Controls = new List<WidgetConfiguration>();
        Controls = new SortedList<int, WidgetConfiguration>();
    }

    public string PageKey { get; set; }
    public string Template { get; set; }
    public int? Percentage { get; set; }
    // replaced by SortedList
    //public IList<WidgetConfiguration> Controls { get; set; }
    public IDictionary<int, WidgetConfiguration> Controls { get; set; }
    public int SchemaVersion { get; set; }
}

请注意,List<WidgetConfiguration>已更改为SortedList<int, WidgetConfiguration>。我如何告诉 NHibernate,当将新项目添加到 SortedList 时,使用的键值应该是 WidgetConfiguration.SlotOrder?

4

2 回答 2

2

NHiberante 对你想要的东西有很好的支持。其实方法不止一种,有两种:

1)映射与<list>

使用支持该<index>列的列表映射。这与对象内部使用的 C# 中的内部索引相同List<T>

小缺点是,你必须保持该列从 0 开始......包括所有数字。与底层 C# 对象相同。但它有效

请在此处查看更多信息:http: //ayende.com/blog/4043/nhibernate-mapping-list 并在此处查看索引集合: http: //nhibernate.info/doc/nh/en/index.html#collections-ofvalues

2) 扩展映射order-by="column_name asc|desc"

这允许使用一些更用户友好的列(具有一些可编辑的值)用于在加载过程中对列表进行排序

请在这里查看更多信息:6.2。映射集合

编辑:按照问题编辑

SortedListNHibernate 再次支持C#映射。请参阅第6.6 节。排序集合

映射应如下所示

<map name="Controls" order-by="SlotOrder" lazy="true" cascade="all-delete-orphan">
    <key column="PageConfigurationId" />
    <index column="SlotOrder" type="System.Int32"/>
    <one-to-many class="WidgetConfiguration"/>
</map>

现在SlotOrder由家长管理。它扮演着Controls SortedList的关键角色。所以我们应该把它的映射改成只读的(应该只存在一个编辑时间点)

<class name="WidgetConfiguration" ...>
  ...
  <property name="SlotOrder" type="System.Int32" insert="false" update="false" />

有了这个映射,我们可以将新项目添加到Controls集合中:

WidgetConfiguration config = ...;
PageConfiguration pageConfig = ...;

pageConfig.Controls[config.SlotOrder] = config;
session.Update(pageConfig);

所以,

  1. 我们已经映射了SortedList(实际上是 interface IDictionary<,>),
  2. SlotOrder用作键(插入,由 NHibernate 更新)
  3. 在 WidgetConfiguration 上可用(只读)

那应该回答有关字典排序和键的问题...请让我知道如果我确实错过了什么...

于 2013-05-18T13:19:28.133 回答
1

你会想使用<List />而不是<Bag />

<bag name="Controls" cascade="all-delete-orphan" lazy="false">
  <key column="PageConfigurationId" />
  <one-to-many class="WidgetConfiguration" />
  <index column="SlotOrder" />
</bag>

我注意到您当前正在将您的收藏映射为Bag. NHibernate 支持三种排序集合-BagSetList

List 有排序语义,我猜你知道,但是当不需要排序时,你通常会使用Set.

因为 aSet要求每个项目只在一个集合中出现一次,所以很容易使用该项目的 Id 上的单个删除语句来删除该项目。ABag不要求集合唯一性,因此 NHibernate 删除项目的唯一方法是删除所有内容,然后重新添加不是已删除项目的每个项目。(相反,将项目添加到 aBag可以比使用 a 更快Set,因为不必强制执行唯一性)

Ayende(NHibernate 的主要贡献者之一)不久前发布了这些:

http://ayende.com/blog/3943/nhibernate-mapping-set

http://ayende.com/blog/4043/nhibernate-mapping-list

于 2013-05-18T13:14:39.733 回答