【问题标题】:How to properly "Singularize" table names with Dapper.Contrib?如何使用 Dapper.Contrib 正确“单一化”表名?
【发布时间】:2020-03-09 12:38:19
【问题描述】:

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

在SQL Server数据库中我有单名的表,和我的POCO类一样,方便匹配和维护。

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

SQL 表“学生”:

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

在输出时我得到一个异常:

对象名称“学生”无效。

我四处寻找解决方案,但找不到可行的示例。一般有两种建议:

  1. 使用数据注释。这个不适合我,因为使用Scaffold-DbContext 从数据库自动创建了很多 POCO 对象。在开发过程中,我对数据库进行了更改,然后再次重新创建 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 类型名称中的最后一个字母,假设Dapper 将最后一个字母“s”添加到类的名称中,我在我的实现中将其删除。 示例:Student =&gt; Students =&gt; Student(s) =&gt; Student

长话短说 - 我找不到一个解决方案来解决如何实现一个将“单一化”我的表名的函数。

我应该如何使用SqlMapperExtensions 或者可能有另一种方法可以在不更改 POCO 类的情况下“单一化”表名?

【问题讨论】:

    标签: c# .net-core dapper dapper-contrib


    【解决方案1】:
    [Table("student")]
    public class Student
    {
        public int StudentId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
    

    就是这样

    【讨论】:

    • 这应该是答案,并且默认情况下它不应该将 s 添加到表中,这是一个糟糕的实现
    【解决方案2】:

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

    首先让我们解决您当前实现 TableNameMapper 的问题;

    1. 您只需设置一次委托。您可以在 Startup 类的 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);
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-08
      • 1970-01-01
      • 1970-01-01
      • 2015-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-09
      相关资源
      最近更新 更多