如何正确地 "Singularize" table 名称与 Dapper.Contrib?

How to properly "Singularize" table names with Dapper.Contrib?

我有一个 .Net Core 3.1 控制台应用程序。

在SQL服务器数据库中我有table单数名称,和我的POCOclass一样,方便匹配和维护

对于插入、更新和删除操作,我想使用 Dapper.Contrib 库。但是当我 运行 Insert function Dapper 在生成的 SQL 查询中复数 table 名称时。

SQL table "Student":

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

C#代码

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

输出时出现异常:

Invalid object name 'Students'.

我四处寻找解决方案,但找不到有效的示例。总的来说有两种推荐:

  1. 使用数据注释。这个对我来说不是 suitable,因为有很多使用 Scaffold-DbContext 从数据库自动创建的 POCO 对象。在开发过程中,我在数据库中进行更改,然后再次重新创建 POCO。此操作删除生成的 POCO classes.

  2. 中所做的所有更改
  3. 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 名称中的最后一个字母,假设 Dapper 添加最后一个字母 "s" 到 class 的名称,我在我的实现中将其删除。 示例:Student => Students => Student(s) => Student.

长话短说 - 我找不到关于如何实现将 "singularize" 我的 table 名字的功能的解决方案。

我应该如何使用 SqlMapperExtensions 或者可能有另一种方法可以 "singularize" table 名称而不在 POCO classes 中进行更改?

您的实现有几个问题,但是,因为您实际上是在返回 type.Name,所以它应该返回您的类型的名称(在本例中是 Student)。

首先让我们解决您当前实施 TableNameMapper;

的问题
  1. 您只需设置一次委托。您可以在 Startup class 的 ConfigureServices 之类的地方执行此操作。现在,您每次打开连接时都会设置它。

  2. 您的实现执行 type.Name.Remove(type.Name.Length - 1, 1); 但您没有将操作结果分配给变量。即使您已经分配了结果,您也只是返回 type.Name

我 运行 你上面的代码,它在 LINQPad 中对我来说工作正常。我建议在调试器的 return type.Name; 行的委托中添加一个断点。如果您需要手动调试,请查看 Visual Studio debugging documentation。检查 type.Name 实际上是什么,然后从那里开始。

这是我 运行 逐字记录的代码:

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);
        }
    }
}
[Table("student")]
public class Student
{
    public int StudentId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

就是这样