NHibernate过滤器集合

时间:2009-09-17 00:32:42

标签: nhibernate filter nhibernate-mapping versioning

使用NHibernate我想过滤一个类中的集合,只包含可能对象的子集。下面我将包括一个示例表数据以帮助解释。我无法使用NHibernate找到这个。

表:数据对象

DataObjectId(PK)/ Name / CurrentVersion

11          "data.txt"      2
12          "info.txt"      3

表:DataObjectVersion

Id / Comment / VersionNumber / DataObjectId(FK)

31   "Genesis"         1          11     <= Ignore this object
32   "Changed data"    2          11     <= Get this object
34   "Genesis"         1          12     <= Ignore this object   
35   "Changed info"    2          12     <= Ignore this object
36   "Added info"      3          12     <= Get this object

我想在一个命令中为每个DataObject加入非外键DataObject.CurrentVersion = DataObjectVersion.VersionNumber。

以下是类和映射文件:

public class DataObject
{
  public virtual int DataObjectId { get; set; }
  public virtual string Name { get; set; }
  public virtual int CurrentVersionNumber { get; set; }
  public virtual IList<DataObjectVersion> Versions { get; set; }
}

<class name="DataObject" table="DataObject" lazy="false">
    <id name="DataObjectId" column="DataObjectId" type="int">
      <generator class="assigned" />
    </id>
    <property name="Name" column="Name" type="String(512)" />
    <property name="CurrentVersionNumber" column="CurrentVersionNumber" type="int" />
    <bag name="Versions" cascade="all-delete-orphan" inverse="true" lazy="false" >
        <key column="DataObjectId" />
        <one-to-many class="DataObjectVersion" />
    </bag>
</class>

public class DataObjectVersion
{
    public virtual int DataObjectVersionId { get; set; }
    public virtual string Comment { get; set; }
    public virtual int VersionNumber { get; set; }
    public virtual int DataObjectId { get; set; }
}

<class name="DataObjectVersion" table="DataObjectVersion" lazy="false">
    <id name="Id" column="DataObjectVersionId" type="int">
      <generator class="assigned" />
    </id>
    <property name="Comment" column="Comment" type="String(512)" />
    <property name="VersionNumber" column="VersionNumber" type="int" />
    <property name="DataObjectId" column="DataObjectId" type="int" />
</class>  

2 个答案:

答案 0 :(得分:11)

如果您想按需过滤集合,使用过滤器是一个有效的选择。 您需要在Version类和bag元素中声明过滤器,并应用NHibernateSession.EnableFilter方法中的过滤器

如果你总是想在包中取一个版本,那么在包的映射中实现'where':

<bag name="Versions" cascade="all-delete-orphan" inverse="true" lazy="false" where="CurrentVersionNumber = Versions.VersionNumber" >
    <key column="DataObjectId" />
    <one-to-many class="DataObjectVersion" />
</bag>

请注意,在'where'中您编写了正确的SQL而不是HQL,因此上面写的正确的SQL可能必须更改以反映您的架构

此外,如果要获取单个对象,则设置一个包,并且相应的IList可能是过度杀伤。 在类中应用公式属性和DataObjectVersion对象可能更合适

类DataObject中的

替换IList
public virtual DataObjectVersion Version { get; set; }

并在映射中将'bag'替换为

行中的内容
<property name="Version" type="DataObjectVersion" update="false" insert="false" formula="(select v.DataObjectVersionId, v.Comments, v.VersionNumber, v.DataObjectId from DataObjectVersion v where v.VersionNumber  = CurrentVersionNumber)" />

再次只允许正确的SQL

我使用了本机数据类型的计算属性(日期时间,字符串等),并且获取实体可能(或可能不)需要更多或不同的东西

最后但并非最不重要的一点是,您可以通过在集合上创建过滤器来获取主要对象DataObject后,在集合上应用过滤器

IList<DataObjectVersion>  fVersion = 
    NHibernateSession.CreateFilter(do.Versions, "where VersionNumber = :ver")
        .SetParameter("ver", do.CurrentVersionNumber)
        .List<DataObjectVersion>();

其中do.Versions集合未初始化,只有在单独的fVersion集合中获取的结果,这是在已经为数据对象提取进行db的往返之后的第二个SELECT。

答案 1 :(得分:0)

据推测,当用户更改数据并且您尝试获取最新数据时,您的VersionNumber会递增。如果您将VersionNumber视为“年龄”字段(即0是最新/最年轻的版本,1是下一个最早的版本等等)那么您的问题就变成了如何获得Age为0的所有实体。这可以使用过滤器完成:http://nhibernate.info/doc/nh/en/index.html#objectstate-filters