1

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!

1 Answer 1

1

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();
Sign up to request clarification or add additional context in comments.

2 Comments

This makes sens, but I don't have Age property in Employee class, so probably I can't assign it to Age property from EmployeeAgeViewModel. Is it right? Any workaround for this ?
@zari how do you call the field that receives the difference? If it's WIEK you can change Age = emp.Age to Age = emp.WIEK. If no field receives the age, you should probably add one. There's no reason to calculate the age with a separate query when the database did so already

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.