我是Dapper微型ORM的新手。到目前为止,我能够将它用于简单的ORM相关的东西,但我不能将数据库列名与类属性映射。

例如,我有如下的数据库表:

Table Name: Person
person_id  int
first_name varchar(50)
last_name  varchar(50)

我有一个叫Person的类:

public class Person 
{
    public int PersonId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

请注意,表中的列名与我试图将从查询结果中获得的数据映射到的类的属性名不同。

var sql = @"select top 1 PersonId,FirstName,LastName from Person";
using (var conn = ConnectionFactory.GetConnection())
{
    var person = conn.Query<Person>(sql).ToList();
    return person;
}

上面的代码将无法工作,因为列名不匹配对象的(Person)属性。在这种情况下,有什么我可以在Dapper手动映射(例如person_id => PersonId)与对象属性的列名?


当前回答

对于所有使用Dapper 1.12的人,以下是你需要做的事情:

添加一个新的列属性类:

  [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property]

  public class ColumnAttribute : Attribute
  {

    public string Name { get; set; }

    public ColumnAttribute(string name)
    {
      this.Name = name;
    }
  }

搜索这一行:

map = new DefaultTypeMap(type);

然后注释掉。

你可以这样写:

        map = new CustomPropertyTypeMap(type, (t, columnName) =>
        {
          PropertyInfo pi = t.GetProperties().FirstOrDefault(prop =>
                            prop.GetCustomAttributes(false)
                                .OfType<ColumnAttribute>()
                                .Any(attr => attr.Name == columnName));

          return pi != null ? pi : t.GetProperties().FirstOrDefault(prop => prop.Name == columnName);
        });

其他回答

这很好:

var sql = @"select top 1 person_id PersonId, first_name FirstName, last_name LastName from Person";
using (var conn = ConnectionFactory.GetConnection())
{
    var person = conn.Query<Person>(sql).ToList();
    return person;
}

Dapper没有允许您指定列属性的功能,我不反对添加对它的支持,只要我们不拉入依赖项。

Kaleb试图解决的问题的简单解决方案是,如果列属性不存在,则接受属性名:

Dapper.SqlMapper.SetTypeMap(
    typeof(T),
    new Dapper.CustomPropertyTypeMap(
        typeof(T),
        (type, columnName) =>
            type.GetProperties().FirstOrDefault(prop =>
                prop.GetCustomAttributes(false)
                    .OfType<ColumnAttribute>()
                    .Any(attr => attr.Name == columnName) || prop.Name == columnName)));

对于所有使用Dapper 1.12的人,以下是你需要做的事情:

添加一个新的列属性类:

  [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property]

  public class ColumnAttribute : Attribute
  {

    public string Name { get; set; }

    public ColumnAttribute(string name)
    {
      this.Name = name;
    }
  }

搜索这一行:

map = new DefaultTypeMap(type);

然后注释掉。

你可以这样写:

        map = new CustomPropertyTypeMap(type, (t, columnName) =>
        {
          PropertyInfo pi = t.GetProperties().FirstOrDefault(prop =>
                            prop.GetCustomAttributes(false)
                                .OfType<ColumnAttribute>()
                                .Any(attr => attr.Name == columnName));

          return pi != null ? pi : t.GetProperties().FirstOrDefault(prop => prop.Name == columnName);
        });

我做以下使用动态和LINQ:

    var sql = @"select top 1 person_id, first_name, last_name from Person";
    using (var conn = ConnectionFactory.GetConnection())
    {
        List<Person> person = conn.Query<dynamic>(sql)
                                  .Select(item => new Person()
                                  {
                                      PersonId = item.person_id,
                                      FirstName = item.first_name,
                                      LastName = item.last_name
                                  }
                                  .ToList();

        return person;
    }

我知道这是一个相对较老的线程,但我想我会把我所做的放在那里。

我希望属性映射能够全局工作。您可以匹配属性名(即默认值),也可以匹配类属性上的列属性。我也不想为我映射到的每个类都设置这个。因此,我创建了一个DapperStart类,我在应用程序启动时调用:

public static class DapperStart
{
    public static void Bootstrap()
    {
        Dapper.SqlMapper.TypeMapProvider = type =>
        {
            return new CustomPropertyTypeMap(typeof(CreateChatRequestResponse),
                (t, columnName) => t.GetProperties().FirstOrDefault(prop =>
                    {
                        return prop.Name == columnName || prop.GetCustomAttributes(false).OfType<ColumnAttribute>()
                                   .Any(attr => attr.Name == columnName);
                    }
                ));
        };
    }
}

很简单。我不知道在写这篇文章的时候会遇到什么问题,但它是有效的。