I am using the Specification pattern, and have a working implementation (taken from the WhoCanHelpMe Codeplex project) for getting data via NLinq, generic repositories and all that goodness.
The root method is:
public IList<Case> GetCasesByUsername(string username)
{
CaseByUserNameSpecification spc = new CaseByUserNameSpecification(username);
return this.caseRepository.FindAll(spc).ToList();
}
The FindAll() method does the following:
public IQueryable<T> FindAll(ILinqSpecification<T, T> specification)
{
return specification.SatisfyingElementsFrom(this.Session.Linq<T>());
}
And, SatisfyingElementsFrom() does this:
public virtual IQueryable<TResult> SatisfyingElementsFrom(IQueryable<T> candidates)
{
if (this.MatchingCriteria != null)
{
return candidates.Where(this.MatchingCriteria).ToList().ConvertAll(this.ResultMap).AsQueryable();
}
return candidates.ToList().ConvertAll(this.ResultMap).AsQueryable();
}
So, for querying cases by CaseNb property of a Case, it's pretty straight-forward. A Specification like the one below works for me and gets the cases I'd want.
public class CaseByCaseNbSpecification : QuerySpecification<User>
{
private string caseNb;
public CaseByCaseNbSpecification(string caseNb)
{
this.caseNb = caseNb;
}
public string UserName
{
get { return this.caseNb; }
}
public override Expression<Func<Case, bool>> MatchingCriteria
{
get { return u => u.CaseNb.Equals(this.caseNb, StringComparison.CurrentCultureIgnoreCase); }
}
}
However, I am at a loss to understand how to do this when crossing multiple entities. What I'd like to have is a Specification that allows me to get Cases by UserName. Basically, in the database, there are three tables and these have been carried into entities. Here's are entities:
Here's the Case class:
public class Case : Entity
{
private ICollection<CaseUser> caseUsers = new HashSet<CaseUser>();
public virtual Patient Patient { get; set; }
public virtual string CaseNb { get; set; }
...
public virtual IEnumerable<CaseUser> CaseUsers { get { return caseUsers; } }
}
Here's the CaseUser:
public class CaseUser : Entity
{
public virtual Case Case { get; set; }
public virtual User User { get; set; }
...
}
And, User:
public class User : Entity
{
private ICollection<CaseUser> caseUsers = new HashSet<CaseUser>();
public virtual Account Account { get; set; }
public virtual string UserName { get; set; }
...
public virtual IEnumerable<CaseUser> CaseUsers { get { return caseUsers; } }
}
How would I write the Expression to get the data across the association table?