我想要对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>
答案 0 :(得分:0)
如果我理解你的问题......
我能以某种方式自定义查询nhibernate设置吗?
......正确的,答案是否定的。
我的意思是,如果您考虑获取ClassA
的实例并对其<set>
集合进行一些分页和过滤。这总是在记忆中完成。 (我们可以用最后附加的贴图来做什么)。
在这种情况下,当您需要对集合项目进行过滤和分页时,我强烈建议您采用其他方式。创建Criteria
(QueryOver
,HQL
),而不是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; }
}
}