First of all, I´m new to DB First, MVC4, Entity Framework 5 AND especially LINQ.
Let´s assume that we have a database with the following tables:
T_Project
- string ProjectNumber (PK)
T_NetworkIpAddress
- string IP (PK)
- …some more attributes…
T_Unit
- Int UnitId (PK)
- string ProjectNumber (FK)
- string IpAddress (FK)
- … some more attributes…
T_ProjectAndIpIntersection
- string ProjectNumber (PK,FK)
- string IpAddress (PK,FK)
Now we want to create a ProjectNumberResultView
where we can search for a ProjectNumber
. The result should show every ProjectNumber
which contains the given searchString
and some additional data from the other tables.
My solution is to create a new ViewModel class:
public class ProjectNumberSearchResult
{
public ProjectNumberSearchResult () {}
public string ProjectNumber { get; set; }
public string UnitId { get; set; }
public string IpAddress { get; set; }
}
And I wrote this method for my SearchController
:
public ActionResult ProjectNumberResultView(string searchString)
{
ViewBag.InputSearchString = searchString;
List<ProjectNumberSearchResult> results = new List<ProjectNumberSearchResult<>();
if (!String.IsNullOrEmpty(searchString))
{
searchString = searchString.Trim();
//find projects
var projects = from p in db.T_ProjectNumber
select p;
projects = projects.Where(s => s.ProjectNumber.Contains(searchString));
var units = from u in db.T_Unit
select u;
foreach (var p in projects.ToList())
{
var pUnits = units.Where(u => u.ProjectNumber.Equals(p.ProjectNumber));
//add only project number when there are no unit entries
if (pUnits.Count() == 0)
results.Add(new ProjectNumberSearchResult () { ProjectNumber = p.ProjectNumber });
//else add object with additional unit data for every unit entry
foreach (var unit in pUnits)
{
var result = new ProjectNumberSearchResult();
result.ProjectNumber = p.ProjectNumber;
result.UnitId = unit.UnitId;
result.IpAddress = unit.IpAddress;
results.Add(result);
}
}
}
return View(results);
}
I hate this solution, because I have to use two foreach iterations…I definitely would prefer a join solution, but I could not work it out.
I´ve tried something like this:
var projects = from p in db.T_ProjectNumber
select p;
projects = projects.Where(s => s.ProjectNumber.Contains(searchString));
var units = from u in db.T_Unit
select u;
//find all projects with or without (there are project number without units) units incl. their additional data
var results = projects.Join(units,
pNumber => pNumber.ProjectNumber,
unitPNumber => unitPNumber.ProjectNumber,
(pNumber, unitPNumber) => new { T_ProjectNumber = pNumber,
T_Unit = unitPNumber })//.Select(??)
//return View(??)
My Questions are:
How about an 'all in one'?:
List<MyViewModel> projects =
(from p in db.T_ProjectNumber
join u in db.unit on p.ProjectNumber equals u.ProjectNumber
where p.ProjectNumber.Contains(searchString)
select new MyViewModel()
{
MyViewModelProperty1 = p.ProjectNumber,
MyViewModelProperty2 = u.Stuff
// etc, etc
}).ToList();
return MyViewModel (a custom object holding only properties that the view requires) to the view.