NHibernate过滤器集合 [英] NHibernate filter collection

查看:191
本文介绍了NHibernate过滤器集合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用NHibernate我想过滤一个类中的集合,只包含一个可能的对象的子集。下面我将包含一个示例表数据来帮助解释。我发现没有办法使用NHibernate。
$ b

Table:DataObject



DataObjectId(PK)/ Name / CurrentVersion



  11data.txt2 
12info.txt3
code $

$ b

Table:DataObjectVersion



Id / Comment / VersionNumber / DataObjectId(FK )



  31Genesis1 11 <=忽略这个对象
32更改数据2 11 < =获取该对象
34创世纪1 12 <=忽略该对象
35更改信息2 12 <=忽略该对象
36添加信息3 12< =获取这个对象

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



以下是类和映射文件:

pre code>公布ic class DataObject
{
public virtual int DataObjectId {get;组; }
public virtual string Name {get;组; }
public virtual int CurrentVersionNumber {get;组; }
公共虚拟IList< DataObjectVersion>版本{get;组; }
}

< class name =DataObjecttable =DataObjectlazy =false>
< id name =DataObjectIdcolumn =DataObjectIdtype =int>
< generator class =assigned/>
< / id>
< property name =Namecolumn =Nametype =String(512)/>
< property name =CurrentVersionNumbercolumn =CurrentVersionNumbertype =int/>
< bag name =Versionscascade =all-delete-orphaninverse =truelazy =false>
< key column =DataObjectId/>
<一对多等级=DataObjectVersion/>
< / bag>
< / class>

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

< class name =DataObjectVersiontable =DataObjectVersionlazy =false>
< id name =Idcolumn =DataObjectVersionIdtype =int>
< generator class =assigned/>
< / id>
< property name =Commentcolumn =Commenttype =String(512)/>
< property name =VersionNumbercolumn =VersionNumbertype =int/>
< property name =DataObjectIdcolumn =DataObjectIdtype =int/>
< / class>


解决方案

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



 < bag name = Versionscascade =all-delete-orphaninverse =truelazy =falsewhere =CurrentVersionNumber = Versions.VersionNumber> 
< key column =DataObjectId/>
<一对多等级=DataObjectVersion/>
< / bag>请注意,在'哪里'你写适当的SQL而不是HQL,因此正确的SQL我写以上可能必须改变,以反映你的模式



另外,如果单个对象被提取设置一个袋子和相应的IList可能是矫枉过正。
在类中使用公式属性和DataObjectVersion对象可能更合适在类DataObject中用

替换IList

  public virtual DataObjectVersion Version {get;组; } 

在映射中用

行代替'bag' b
$ b

 < property name =Versiontype =DataObjectVersionupdate =falseinsert =falseformula =(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,VersionNumber =:ver)
.SetParameter(ver,do.CurrentVersionNumber)
.List< DataObjectVersion>();

其中do.Versions集合未初始化,只有在单独的fVersion集合中获取的结果是第二个SELECT之后,已经做了往返数据库获取的数据库。


Using NHibernate I want to filter a collection in a class to contain ONLY a subset of possible objects. Below I am including a sample table data to help explain. I can find no way to do this using NHibernate.

Table:DataObject

DataObjectId(PK) / Name / CurrentVersion

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

Table: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

I want to join on a non-foreign key DataObject.CurrentVersion = DataObjectVersion.VersionNumber for each DataObject in one command.

Here are the classes and mapping files:

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>  

解决方案

if you want to filter the collection on demand, using a filter is a valid choice. You would need to declare the filter on both the Version class and in the bag element and apply the filter from the NHibernateSession.EnableFilter method

if you always want to fetch a single Version in the bag then implement a 'where' in the mapping of the bag:

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

note that in the 'where' you write proper SQL not HQL and as such the proper SQL i write above probably has to be changed to reflect your schema

Additionally if a single object is to be fetched setting up a bag and the according IList may be an overkill. Applying a formula property and a DataObjectVersion object in the class may be more appropriate

in the class DataObject replace the IList with

public virtual DataObjectVersion Version { get; set; }

and in the mapping replace the 'bag' with something in the lines of

<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)" />

again only proper SQL is allowed

i've used computed properties with native datatypes (datetime, string etc) and fetching an Entity may (or may not) need something more or different

Last but not least, you could apply a filter on the collection after you have fetched the primary object DataObject by creating a filter on the collection

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

where the do.Versions collection is not initialized, only the results fetched in the separate fVersion collection and this is a second SELECT after already having made the round-trip to the db for the DataObject fetch.

这篇关于NHibernate过滤器集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆