我认为一种方法是使用过滤器。要做的第一件事是通过过滤器类创建过滤器定义,如下所示:
public class MonthsFilter : FilterDefinition
{
public MonthsFilter()
{
WithName("MonthsFilter")
.AddParameter("startMonths", NHibernateUtil.Int32)
.AddParameter("endMonths", NHibernateUtil.Int32);
}
}
然后,您需要将过滤器添加到
ClassMap
为了一个,为了
BList
财产,通过
ApplyFilter
方法:
internal class AMapping : ClassMap<A>
{
public AMapping()
{
Table("AObjects");
Id(x => x.Id, "id");
Map(x => x.Active, "active");
HasMany(x => x.BList)
.Table("BObjects")
.KeyColumn("foreign_id")
.Component(y => {
y.Map(b => b.Month, "month");
y.Map(b => b.Year, "year");
}).ApplyFilter<MonthsFilter>("year * 12 + month BETWEEN :startMonths and :endMonths");
}
}
最后,您需要在发出查询之前启用过滤器,类似于以下内容:
using (var session = sessionFactory.OpenSession())
{
// Enable filter and pass parameters
var startMonthsValue = 2000 * 12 + 1; // january 2000
var endMonthsValue = 2010 * 12 + 3; // march 2010
session.EnableFilter("MonthsFilter")
.SetParameter("startMonths", startMonthsValue)
.SetParameter("endMonths", endMonthsValue);
// Create and execute query (no filter for B needed here)
var list = session.QueryOver<A>()
.Fetch(x => x.BList).Eager // Eager fetch to avoid the N+1 problem due to BList lazy load
.Where(x => x.Active)
.TransformUsing(Transformers.DistinctRootEntity) // List only distinct A entities, to avoid duplicated entries due to eager fetch one-to-many relation
.List();
// Do whatever you want with the results
foreach (var item in list)
{
Console.WriteLine("A id: {0} - B children count: {1}", item.Id, item.BList.Count());
}
}
一个完整的工作示例:
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Mapping;
using NHibernate;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace NHibernateTests
{
public class A
{
public virtual int Id { get; set; }
public virtual bool Active { get; set; }
public virtual IEnumerable<B> BList { get; set; }
}
public class B
{
public virtual int Month { get; set; }
public virtual int Year { get; set; }
}
internal class AMapping : ClassMap<A>
{
public AMapping()
{
Table("AObjects");
Id(x => x.Id, "id");
Map(x => x.Active, "active");
HasMany(x => x.BList)
.Table("BObjects")
.KeyColumn("foreign_id")
.Component(y => {
y.Map(b => b.Month, "month");
y.Map(b => b.Year, "year");
}).ApplyFilter<MonthsFilter>("year * 12 + month BETWEEN :startMonths and :endMonths");
}
}
public class MonthsFilter : FilterDefinition
{
public MonthsFilter()
{
WithName("MonthsFilter")
.AddParameter("startMonths", NHibernateUtil.Int32)
.AddParameter("endMonths", NHibernateUtil.Int32);
}
}
class Program
{
static void Main(string[] args)
{
var sessionFactory = CreateNHibernateSessionFactory();
using (var session = sessionFactory.OpenSession())
{
// Enable filter and pass parameters
var startMonthsValue = 2000 * 12 + 1; // january 2000
var endMonthsValue = 2010 * 12 + 3; // march 2010
session.EnableFilter("MonthsFilter")
.SetParameter("startMonths", startMonthsValue)
.SetParameter("endMonths", endMonthsValue);
// Create and execute query (no filter needed here)
var list = session.QueryOver<A>()
.Fetch(x => x.BList).Eager // Eager fetch to avoid the N+1 problem due to BList lazy load
.Where(x => x.Active)
.TransformUsing(Transformers.DistinctRootEntity) // List only distinct A entities, to avoid duplicated entries due to eager fetch one-to-many relation
.List();
// Do whatever you want with the results
foreach (var item in list)
{
Console.WriteLine("A id: {0} - B children count: {1}", item.Id, item.BList.Count());
}
}
Console.WriteLine("Press ENTER to continue...");
Console.ReadLine();
}
static ISessionFactory CreateNHibernateSessionFactory()
{
FluentConfiguration fc = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2012.ConnectionString("Server=.\\SQLEXPRESS;Database=NHibernateTests;Trusted_Connection=True;"))
.Mappings(m => {
m.FluentMappings
.AddFromAssembly(Assembly.GetExecutingAssembly());
});
var config = fc.BuildConfiguration();
return config.SetProperty(NHibernate.Cfg.Environment.ReleaseConnections, "on_close")
.BuildSessionFactory();
}
}
}
有关筛选器的详细信息: