Как правильно "Singularize" имена таблиц с Dapper.Contrib? - PullRequest
3 голосов
/ 09 марта 2020

У меня есть консольное приложение. Net Core 3.1.

В SQL База данных сервера У меня есть таблицы с единичными именами, такими же, как у моих классов POCO, что удобно для сопоставления и ведения.

Для операций вставки, обновления и удаления я хочу использовать библиотеку Dapper.Contrib. Но когда я запускаю функцию Вставить, Dapper преобразует имена таблиц в сгенерированные SQL запросы.

SQL таблица "Student":

CREATE TABLE Student
    StudentId int NOT NULL PRIMARY KEY,
    FirstName varchar(50),
    LastName varchar(50)

C# code

public class Student
{
    public int StudentId {get; set;}
    public string FirstName {get; set;}
    public string LastName {get; set;}
}


class Program
{
    static void Main(string[] args)
    {
        var students = new List<Student>()
            {
                new Student { StudentId = 1, FirstName = "John", LastName = "Doe"},
                new Student { StudentId = 2, FirstName = "Tony", LastName = "Montana"}
            }

        long result;
        using (var cn = new SqlConnection(connString))
            {
                        result = cn.Insert(students);
            }
    }
}

При выводе я получаю исключение:

Недопустимое имя объекта «Студенты».

Я просмотрел поиски решения, но не смог найти работающего пример. Обычно существует два вида рекомендаций:

  1. Использование аннотаций данных . Этот мне не подходит, так как многие объекты POCO создаются автоматически из базы данных с использованием Scaffold-DbContext. В процессе разработки я делаю изменения в базе данных, а затем заново создаю POCO. Эта операция удаляет все изменения, сделанные в сгенерированных классах POCO.

  2. Использование делегата SqlMapperExtensions:

    SqlMapperExtensions.TableNameMapper = (type) => { // do something here to pluralize the name of the type return type.Name; };

Я не знаю, как правильно использовать этот делегат и где его разместить. Я экспериментировал некоторое время, но уверен, что не правильно его использую:

using (var cn = new SqlConnection(connString))
    {
            SqlMapperExtensions.TableNameMapper = (type) =>
            {
                type.Name.Remove(type.Name.Length - 1, 1);
                return type.Name;
            };
            result = cn.Insert(students);
    }

В этой строке кода type.Name.Remove(type.Name.Length - 1, 1); Я попытался реализовать функцию, которая обрезает последнюю букву в имя типа Student, при условии, что Даппер добавляет последнюю букву "s" к имени класса, и я удаляю его в своей реализации. Пример: Student => Students => Student(s) => Student.

Короче говоря - я не смог найти решение о том, как реализовать функцию, которая будет "сингулярно" использовать имена моих таблиц.

Как использовать SqlMapperExtensions или, может быть, существует другой подход, который может "сингулярно" именовать таблицы без внесения изменений в классы POCO?

Ответы [ 2 ]

3 голосов
/ 09 марта 2020

У вашей реализации есть пара проблем, но, поскольку вы по сути возвращаете type.Name, она должна возвращать имя вашего типа (в данном случае Student).

Сначала давайте обратимся к проблемы с вашей текущей реализацией TableNameMapper;

  1. Вам необходимо установить делегата только один раз. Вы можете сделать это где-нибудь как ConfigureServices вашего Startup класса. Прямо сейчас вы устанавливаете его каждый раз, когда открываете свое соединение.

  2. Ваша реализация выполняет type.Name.Remove(type.Name.Length - 1, 1);, но вы не присваиваете результат операции переменной. Даже если вы присвоили результат, вы все равно возвращаете type.Name.

Я запустил код, который вы указали выше, и он работает правильно для меня в LINQPad. Я бы предложил добавить точку останова в вашем отладчике в строку return type.Name; вашего делегата. Если вам нужна ручная отладка, взгляните на документацию по отладке Visual Studio . Проверьте, что на самом деле type.Name и go оттуда.

Вот код, который я дословно запустил:

public class Student
{
    public int StudentId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

class Program
{
    static void Main()
    {
        SqlMapperExtensions.TableNameMapper = (type) => type.Name;

        var students = new List<Student>
        {
            new Student { StudentId = 1, FirstName = "John", LastName = "Doe" },
            new Student { StudentId = 2, FirstName = "Tony", LastName = "Montana" }
        };

        using (var sqlConnection = new SqlConnection(connectionString))
        {
            sqlConnection.Insert(students);
        }
    }
}
0 голосов
/ 22 апреля 2020
[Table("student")]
public class Student
{
    public int StudentId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Это путь

...