Как использовать функции SQL в Dapper? - PullRequest
1 голос
/ 07 марта 2019

Я делаю приложение, которое тестирует выбранные ORM (EF, NHibernate, Dapper).Я разрабатываю его в .NET Core 2.0 и использую для этого базу данных AdventureWorks.У меня проблема с запросом, который возвращает всех сотрудников, которым более 50 лет. Я не знаю, как я могу использовать функцию SQL DateDiff, или мне нужен какой-то другой способ сделать это с помощью SQL.Вот фрагмент из моего класса DapperRepository:

  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;
    }

На данный момент я делаю два запроса, но мне интересно, могу ли я сделать это только одним запросом или, возможно, другим способом.

Спасибо за помощь!

1 Ответ

1 голос
/ 07 марта 2019

Вы уже правильно используете функцию. Проблема в том, что вы пытаетесь вычислить разницу от поля. Это предотвращает использование сервером любых индексов, которые покрывают это поле.

Вычислите дату отсечения в вашем коде, например, var cutoff=DateTime.Today.AddYears(-50); и передайте отсечение в качестве параметра в запрос в качестве параметра, например:

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();
...