I have a strange requirement I'm not sure how to solve.
Assuming the following class definition:
public class Client
{
public Guid Id { get; set; }
public String Person { get; set; }
public IList<Client> SecondaryClients { get; set; }
public Client PrimaryClient { get; set; }
}
public class Person
{
public Guid Id { get; set; }
public String Name { get; set; }
}
When a user searches the system for a client by name, it needs to search all primary clients as well as secondary clients that are one hop away. (ie if the PrimaryClient is set then we need to check the PrimaryClient.Person.Name property, however we don't have to worry about the PrimaryClient.PrimaryClient.)
Using DetachedCriteria, I have the following:
var clientQuery = DetachedCriteria.For<Client>();
clientQuery.Add(Restrictions.Disjunction()
.Add(Restrictions.Like("Person.Surname", lastName, MatchMode.Start))
.Add(Restrictions.Like("PrimaryClient.Person.Surname", lastName, MatchMode.Start))
.Add(Restrictions.Like("SecondaryClients.Person.Surname", lastName, MatchMode.Start)));
var session = OpenSession();
session.BeginTransaction();
var clients = clientQuery.GetExecutableCriteria(session).Future<Client>();
session.Transaction.Commit();
session.Close();
Now obviously, this is way off. Doing some digging around I discovered that I needed to setup Aliases. The first was easy for finding the Person.Surname:
var clientQuery = DetachedCriteria.For<Client>();
clientQuery = clientQuery.CreateAlias("Person", "p");
clientQuery.Add(Restrictions.Disjunction()
.Add(Restrictions.Like("p.Surname", lastName, MatchMode.Start))
.Add(Restrictions.Like("PrimaryClient.Person.Surname", lastName, MatchMode.Start))
.Add(Restrictions.Like("SecondaryClients.Person.Surname", lastName, MatchMode.Start)));
var session = OpenSession();
session.BeginTransaction();
var clients = clientQuery.GetExecutableCriteria(session).Future<Client>();
session.Transaction.Commit();
session.Close();
However, for the life of me I'm not sure what I can do for the alias of PrimaryClient.Person. Am I going down the wrong path here? Any help would be appreciated.
NOTE: I forgot to mention originally. It is possible that SecondaryClients and PrimaryClient are null.
For those keeping score, I was able to figure out how to do this. I'm not sure if there's a more efficient way, however here's how I setup the query using DetachedCriteria.
var clientQuery = DetachedCriteria.For<Client>("Client");
clientQuery = clientQuery.CreateAlias("Person", "p");
var primaryQuery = DetachedCriteria.For<Client>("Primary");
primaryQuery.SetProjection(Projections.Property("Primary.Id"));
primaryQuery.Add(Restrictions.EqProperty("Client.PrimaryClient", "Primary.Id"));
primaryQuery.CreateAlias("Person", "p");
primaryQuery.Add(Restrictions.Like("p.Surname", lastName, MatchMode.Start));
var secondaryQuery = DetachedCriteria.For<Client>();
secondaryQuery.SetProjection(Projections.Property("Id"));
secondaryQuery.CreateCriteria("SecondaryClients")
.CreateCriteria("Person")
.Add(Restrictions.Like("Surname", lastName, MatchMode.Start));
clientQuery.Add(Restrictions.Disjunction()
.Add(Restrictions.Like("p.Surname", lastName, MatchMode.Start))
.Add(Subqueries.Exists(primaryQuery))
.Add(Subqueries.PropertyIn("Id", secondaryQuery)));