Reputation: 67
I am doing an application that benchmarks selected ORMs (EF,NHibernate,Dapper). I am developing it in .NET Core 2.0 and I am using AdventureWorks database for it. I have a problem with the query that returns all employees that has age more than 50. I don't know how can I use SQL function DateDiff, or I need some other way to do this via SQL. Here is the snippet from my DapperRepository class:
public List<EmployeeAgeViewModel> GetEmployeesOlderThan50()
{
string sqlQuery = @"select Person.BusinessEntityID as PersonID, Person.LastName,
Person.FirstName,
Employee.BusinessEntityID as EmployeeID,
Employee.Gender,
Employee.BirthDate,
Employee.HireDate,
DATEDIFF(YEAR, Employee.BirthDate, GETDATE()) as [WIEK]
FROM Person.Person
JOIN HumanResources.Employee
ON Person.BusinessEntityID = Employee.BusinessEntityID
WHERE DATEDIFF(YEAR, Employee.BirthDate, GETDATE()) >= 50
ORDER BY Wiek DESC";
var employeesAge = _con.Query<Person, Employee, EmployeeAgeViewModel>(sqlQuery,
(per, emp) => new EmployeeAgeViewModel()
{
FirstName = per.FirstName,
LastName = per.LastName,
Gender = emp.Gender == "M" ? Models.Helpers.Enums.Gender.M : Models.Helpers.Enums.Gender.F,
BirthDate = emp.BirthDate,
HireDate = emp.HireDate,
Age = -1
//Description: We cannot use query below because it is inside other query. So I am assiging -1 and then after I close
// current query I am doing the second one to get the age.
//_con.Query<int>("select DATEDIFF(year, GETDATE(), @date)", new { date = emp.BirthDate }).SingleOrDefault()
},
splitOn: "EmployeeID")
.ToList();
string sqlQueryAge = "select DATEDIFF(year, @date, GETDATE())";
foreach (var employee in employeesAge)
{
employee.Age = (int)_con.ExecuteScalar(sqlQueryAge, new { date = employee.BirthDate });
}
return employeesAge;
}
For now I am doing two queries, but I am wondering if I can do it only using one query or maybe some different way.
Thanks for help!
Upvotes: 1
Views: 2457
Reputation: 131364
You're already using the function correctly. The problem is that you try to calculate the difference from a field. This prevents the server from using any indexes that cover that field.
Calculate the cutoff date in your code, eg var cutoff=DateTime.Today.AddYears(-50);
and pass the cutoff as a parameter to the query as a parameter, eg :
var cutoff=DateTime.Today.AddYears(-50);
var sqlQuery = @"select Person.BusinessEntityID as PersonID, Person.LastName,
Person.FirstName,
Employee.BusinessEntityID as EmployeeID,
Employee.Gender,
Employee.BirthDate,
Employee.HireDate,
DATEDIFF(YEAR, Employee.BirthDate, GETDATE()) as Age
FROM Person.Person
JOIN HumanResources.Employee
ON Person.BusinessEntityID = Employee.BusinessEntityID
WHERE Employee.BirthDate <= @cutoff
ORDER BY Age DESC";
var employeesAge = _con.Query<Person, Employee, EmployeeAgeViewModel>(sqlQuery,
new {cutoff},
(per, emp) => new EmployeeAgeViewModel()
{
FirstName = per.FirstName,
LastName = per.LastName,
Gender = emp.Gender == "M" ? Models.Helpers.Enums.Gender.M : Models.Helpers.Enums.Gender.F,
BirthDate = emp.BirthDate,
HireDate = emp.HireDate,
Age = emp.Age
},
splitOn: "EmployeeID")
.ToList();
Upvotes: 1