自定义nhibernate <set>查询</set>

时间:2012-11-21 15:15:42

标签: nhibernate mapping set one-to-many outer-join

我想要对ClassA.ClassBCollection属性进行过滤和分页。我需要动态更改过滤。

默认查询将导致类似:

    select * from ClassA 
             left outer join ClassB 
             on id == FK_ClassB

我能以某种方式自定义查询nhibernate设置吗?

映射:

<class name="ClassA">
    <property name="Name" />
    <set name="ClassBCollection">
      <key column="FK_ClassB" on-delete="cascade" />
      <one-to-many class="ClassB" />
    </set>
  </class>

  <class name="ClassB">
    <property name="Something"/>
  </class>

2 个答案:

答案 0 :(得分:0)

如果我理解你的问题......

  

我能以某种方式自定义查询nhibernate设置吗?

......正确的,答案是否定的。

我的意思是,如果您考虑获取ClassA的实例并对其<set>集合进行一些分页和过滤。这总是在记忆中完成。 (我们可以用最后附加的贴图来做什么)

我们可以改变方法

在这种情况下,当您需要对集合项目进行过滤和分页时,我强烈建议您采用其他方式。创建CriteriaQueryOverHQL),而不是ClassA,而是 ClassB

首先,我们必须扩展ClassB映射:

<class name="ClassB">
  <property name="Something" />
  <many-to-one name="ClassA" column="FK_ClassB" fetch="join" />
</class>

然后像这样创建一个Criteria

var criteria = NHSession.Current.CreateCriteria<ClassB>();

criteria
    .Add(new InExpression("ClassA", new object[] {1})) // id of one or more ClassA
    .AddOrder(new Order("Something", true))            // Order By
    .SetFirstResult(2)                                 // Skip
    .SetMaxResults(10);                                // Take

var list = criteria.List<ClassB>();

因为我们使用了ClassA fetch="join"的映射,所以得到的SQL语句将与此问题中的第一个片段非常相似。

这样,我们可以实现所需的SQL Select,但我们不能直接使用ClassA.ClassBCollection。我们这样做了......

注意:

我们可以影响<set>映射的过滤器/分页是where子句中的静态过滤器和获取值的样式。

在将ClassBCollection作为ClassA的属性加载时,将始终评估Where子句。它可能像where="IsActive=true"

如果ClassA可以在ClassBCollection中拥有大量项目,我们可以管理它们将如何被借出。非常有效的方法是属性批量大小documented here

答案 1 :(得分:0)

  

我能以某种方式自定义查询nhibernate设置吗?

我不完全确定这意味着什么。如果您的意思是,我可以在集合上查询和使用WHERE子句,答案是肯定的。方法如下:

[TestFixture]
public class StackOverflowQuestion13496270Tests
{
    public ISession session;

    [SetUp]
    public void SetUp()
    {
        session = // Get the current NHibernate session
    }

    [Test]
    public void Query_ClassA()
    {
        var results = session.Query<ClassA>()
            .Where( x => x.ClassBCollection.Any( y => y.Name == "Bob" ) )
            .Fetch( x => x.ClassBCollection )
            .Skip( 0 )
            .Take( 50 )
            .ToList();
    }

    [Test]
    public void Query_ClassB()
    {
        var results = session.Query<ClassB>()
            .Where( x => x.Name == "Bob" )
            .Fetch( x => x.ClassAParent )
            .Skip( 0 )
            .Take( 50 )
            .ToList();
    }

    public class ClassA
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual IList<ClassB> ClassBCollection { get; set; }
    }

    public class ClassB
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }

        // Add this and the appropriate mapping modifications to be able to navigate back to the parent
        public virtual ClassA ClassAParent { get; set; }
    }
}