I have a many-to-many relationship which I am trying to query. My problem is very similar to one detailed by Phillip Haydon here so I am going to liberally borrow his diagrams and explanation.
Phillip had the following many-to-many relationship between Jobs and Roles (sorry I can’t embed images yet):
data schema
Phillip needed to query all the roles which were not assigned to a job. His solution was the following:
Role roleAlias = null;
var existing = QueryOver.Of<JobRole>()
.Where(x => x.Job.JobId == jobId)
.And(x => x.Role.RoleId != roleId)
.And(x => x.Role.RoleId == roleAlias.RoleId)
.Select(x => x.Role);
result = Session.QueryOver<Role>(() => roleAlias)
.Where(x => x.IsEnabled)
.WithSubquery.WhereNotExists(existing)
.OrderBy(x => x.Name).Asc
.List();
This was very helpful however it appears that in this solution there is an entity for each table; Job, JobRole, and Role. JobRole has both a Job and a Role. Probably something like this:
public class Job
{
public int JobId {get;set;}
public string Name {get; set;}
public bool IsEnabled {get;set;}
public bool IsDefault {get;set;}
}
public class Role
{
public int RoleId {get;set}
public string Name {get;set}
public bool IsEnabled {get;set}
public string RoleType {get;set}
}
public class JobRole
{
public Job Job {get;set}
public Role Role {get;set;}
}
This conflicts with the pattern I have seen for modeling many-to-many relationships, specifically in sharp architecture examples and from advice here. In those examples and in my case, I have only two classes, Job and Role. Something like this:
public class Job
{
public int JobId {get;set;}
public string Name {get; set;}
public bool IsEnabled {get;set;}
public bool IsDefault {get;set;}
public IList<Role> Roles {get;set;}
}
public class Role
{
public int RoleId {get;set}
public string Name {get;set}
public bool IsEnabled {get;set}
public string RoleType {get;set}
public List<Job> Jobs {get;set;}
}
In my case, I need to find all jobs which only have roles. I’ve tried something like this
Job job = null;
Role role = null;
var jobs = Session.QueryOver(() => job)
.WithSubquery
.WhereExists(
QueryOver.Of(() => role)
.JoinAlias(() => role.Jobs, () => job))
.List().ToList();
but NHibernate requires that the projection for the select in the WhereExists and complains if one is not provided, which makes sense to me.
With my model is it even possible to do a QueryOver Subquery with WhereExists?
Thanks in advance.
Mapping for Job:
and mapping
In my case produce following SQL (beautified):
and returns only jobs with roles as you want