Working with NHibernate's query criteria API is logical, but sometimes I slip. For example, say I have a class Timesheet and the timesheet has property (which is also mapped) named Employee and a component named PayrollPeriod:
public class Timesheet : DomainObject<int>, ITimesheet
{
private IEmployee _employee;
public virtual IEmployee Employee
{
get
{
return _employee;
}
}
private IRange<DateTime> _payrollPeriod = new Range<DateTime>(DateTime.MinValue, DateTime.MaxValue);
public virtual IRange<DateTime> PayrollPeriod
{
get
{
return _payrollPeriod;
}
}
}
Now, when i query for a timesheet i want to get a timesheet with an Employee.Id = 36.
I might think the Criteria would look like this:
ICriteria crit = session.CreateCriteria(typeof(Timesheet);
crit.Add(Expression.Eq("Employee.Id",36));
Now, that would be fun but it would be wrong. Since Employee is a mapped class, it is really and association. So I neeed to do the following:
ICriteria crit = session.CreateCriteria(typeof(Timesheet);
crit.CreateCriteria("Employee").Add(Expression.Eq("Id",36));
This creates a SubCriteria object via what is called an 'association path' which is really just the property name. This tells NHibby to nest a criteria inside the main Timesheet criteria (inner join).
Now, let's say I have a component inside Timesheet called PayrollPeriod. This PayrollPeriod class might have two properties: Start and End:
public interface IRange<T>: IValueObject where T : IComparable<T>
{
T Start { get;}
T End { get;}
bool Contains(T valueToFind);
}
When I want to query on the Timesheet for a PayrollPeriod which matched certain criteria, I will employ the period notation 'Component.PropertyName' to get there. So it would look like this:
ICriteria crit = session.CreateCriteria(typeof(Timesheet);
crit.Add(Expression.Eq("PayrollPeriod.Start",new DateTime(2006,9,9)));
If I were to try to do an association type mapping like we did with Employee, we'd find NHibby complaining because it thinks we are trying to tell it that 'Start' is a property of 'Timesheet'.