我是Dapper Micro ORM的新手.到目前为止,我能够将它用于简单的ORM相关内容,但我无法使用类属性映射数据库列名.例如:
我有如下数据库表:
Table Name: Person
person_id int
first_name varchar(50)
last_name varchar(50)
Run Code Online (Sandbox Code Playgroud)
我有一个名为Person的课程
public class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
请注意,表中的列名与我尝试映射查询结果的数据的类的属性名不同.
var sql = @"select top 1 PersonId,FirstName,LastName from Person";
using (var conn = ConnectionFactory.GetConnection())
{
var person = conn.Query<Person>(sql).ToList();
return person;
}
Run Code Online (Sandbox Code Playgroud)
上面的代码不起作用,因为列名与对象的(Person)属性不匹配.在这种情况下,我可以在Dapper中手动映射(例如person_id => PersonId)具有对象属性的列名吗?
任何线索或帮助将受到高度赞赏.
Kal*_*son 182
Dapper现在支持自定义列到属性映射器.它通过ITypeMap接口完成.Dapper提供了一个CustomPropertyTypeMap类,可以完成大部分工作.例如:
Dapper.SqlMapper.SetTypeMap(
typeof(TModel),
new CustomPropertyTypeMap(
typeof(TModel),
(type, columnName) =>
type.GetProperties().FirstOrDefault(prop =>
prop.GetCustomAttributes(false)
.OfType<ColumnAttribute>()
.Any(attr => attr.Name == columnName))));
Run Code Online (Sandbox Code Playgroud)
而型号:
public class TModel {
[Column(Name="my_property")]
public int MyProperty { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
值得注意的是,CustomPropertyTypeMap的实现要求该属性存在并匹配其中一个列名,否则将不会映射该属性.该DefaultTypeMap类提供的标准功能,并且可以被利用来改变这种行为:
public class FallbackTypeMapper : SqlMapper.ITypeMap
{
private readonly IEnumerable<SqlMapper.ITypeMap> _mappers;
public FallbackTypeMapper(IEnumerable<SqlMapper.ITypeMap> mappers)
{
_mappers = mappers;
}
public SqlMapper.IMemberMap GetMember(string columnName)
{
foreach (var mapper in _mappers)
{
try
{
var result = mapper.GetMember(columnName);
if (result != null)
{
return result;
}
}
catch (NotImplementedException nix)
{
// the CustomPropertyTypeMap only supports a no-args
// constructor and throws a not implemented exception.
// to work around that, catch and ignore.
}
}
return null;
}
// implement other interface methods similarly
// required sometime after version 1.13 of dapper
public ConstructorInfo FindExplicitConstructor()
{
return _mappers
.Select(mapper => mapper.FindExplicitConstructor())
.FirstOrDefault(result => result != null);
}
}
Run Code Online (Sandbox Code Playgroud)
有了它,就可以很容易地创建一个自定义类型映射器,如果它们存在,它们将自动使用属性,否则将回退到标准行为:
public class ColumnAttributeTypeMapper<T> : FallbackTypeMapper
{
public ColumnAttributeTypeMapper()
: base(new SqlMapper.ITypeMap[]
{
new CustomPropertyTypeMap(
typeof(T),
(type, columnName) =>
type.GetProperties().FirstOrDefault(prop =>
prop.GetCustomAttributes(false)
.OfType<ColumnAttribute>()
.Any(attr => attr.Name == columnName)
)
),
new DefaultTypeMap(typeof(T))
})
{
}
}
Run Code Online (Sandbox Code Playgroud)
这意味着我们现在可以轻松支持需要使用属性的地图的类型:
Dapper.SqlMapper.SetTypeMap(
typeof(MyModel),
new ColumnAttributeTypeMapper<MyModel>());
Run Code Online (Sandbox Code Playgroud)
Mar*_*ell 66
有一段时间,以下应该有效:
Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true;
Run Code Online (Sandbox Code Playgroud)
Sam*_*ron 63
这很好用:
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;
}
Run Code Online (Sandbox Code Playgroud)
Dapper没有允许你指定列属性的工具,我不反对添加对它的支持,只要我们不引入依赖.
Ran*_*ton 28
这是一个简单的解决方案,不需要允许您将基础设施代码保留在POCO之外的属性.
这是一个处理映射的类.如果映射了所有列,字典将起作用,但此类允许您仅指定差异.此外,它还包括反向映射,因此您可以从列中获取字段,从字段中获取列,这在执行生成sql语句等操作时非常有用.
public class ColumnMap
{
private readonly Dictionary<string, string> forward = new Dictionary<string, string>();
private readonly Dictionary<string, string> reverse = new Dictionary<string, string>();
public void Add(string t1, string t2)
{
forward.Add(t1, t2);
reverse.Add(t2, t1);
}
public string this[string index]
{
get
{
// Check for a custom column map.
if (forward.ContainsKey(index))
return forward[index];
if (reverse.ContainsKey(index))
return reverse[index];
// If no custom mapping exists, return the value passed in.
return index;
}
}
}
Run Code Online (Sandbox Code Playgroud)
设置ColumnMap对象并告诉Dapper使用映射.
var columnMap = new ColumnMap();
columnMap.Add("Field1", "Column1");
columnMap.Add("Field2", "Column2");
columnMap.Add("Field3", "Column3");
SqlMapper.SetTypeMap(typeof (MyClass), new CustomPropertyTypeMap(typeof (MyClass), (type, columnName) => type.GetProperty(columnMap[columnName])));
Run Code Online (Sandbox Code Playgroud)
lio*_*far 25
我使用动态和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;
}
Run Code Online (Sandbox Code Playgroud)
Oli*_*ver 12
取自目前在Dapper 1.42上的Dapper Tests.
// custom mapping
var map = new CustomPropertyTypeMap(typeof(TypeWithMapping),
(type, columnName) => type.GetProperties().FirstOrDefault(prop => GetDescriptionFromAttribute(prop) == columnName));
Dapper.SqlMapper.SetTypeMap(typeof(TypeWithMapping), map);
Run Code Online (Sandbox Code Playgroud)
Helper类从Description属性中获取名称(我个人使用过类似@kalebs的例子)
static string GetDescriptionFromAttribute(MemberInfo member)
{
if (member == null) return null;
var attrib = (DescriptionAttribute)Attribute.GetCustomAttribute(member, typeof(DescriptionAttribute), false);
return attrib == null ? null : attrib.Description;
}
Run Code Online (Sandbox Code Playgroud)
类
public class TypeWithMapping
{
[Description("B")]
public string A { get; set; }
[Description("A")]
public string B { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
Bra*_*ess 11
实现此目的的一种简单方法是在查询中的列上使用别名.如果您的数据库列是,PERSON_ID并且您的对象的属性是ID您可以select PERSON_ID as Id ...在您的查询中执行,Dapper将按预期选择它.
mxm*_*ile 10
与映射混淆是边缘进入真正的ORM土地.而不是与它斗争并使Dapper保持其真正的简单(快速)形式,只需稍微修改您的SQL:
var sql = @"select top 1 person_id as PersonId,FirstName,LastName from Person";
Run Code Online (Sandbox Code Playgroud)
在打开与数据库的连接之前,请为每个poco类执行以下代码:
// Section
SqlMapper.SetTypeMap(typeof(Section), new CustomPropertyTypeMap(
typeof(Section), (type, columnName) => type.GetProperties().FirstOrDefault(prop =>
prop.GetCustomAttributes(false).OfType<ColumnAttribute>().Any(attr => attr.Name == columnName))));
Run Code Online (Sandbox Code Playgroud)
然后将数据注释添加到您的poco类,如下所示:
public class Section
{
[Column("db_column_name1")] // Side note: if you create aliases, then they would match this.
public int Id { get; set; }
[Column("db_column_name2")]
public string Title { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
在那之后,你们都准备好了.只需进行查询调用,例如:
using (var sqlConnection = new SqlConnection("your_connection_string"))
{
var sqlStatement = "SELECT " +
"db_column_name1, " +
"db_column_name2 " +
"FROM your_table";
return sqlConnection.Query<Section>(sqlStatement).AsList();
}
Run Code Online (Sandbox Code Playgroud)
这是对其他答案的回避。这只是我管理查询字符串的一个想法。
人物.cs
public class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public static string Select()
{
return $"select top 1 person_id {nameof(PersonId)}, first_name {nameof(FirstName)}, last_name {nameof(LastName)}from Person";
}
}
Run Code Online (Sandbox Code Playgroud)
接口方法
using (var conn = ConnectionFactory.GetConnection())
{
var person = conn.Query<Person>(Person.Select()).ToList();
return person;
}
Run Code Online (Sandbox Code Playgroud)
如果您使用 .NET 4.5.1 或更高版本,请检查Dapper.FluentColumnMapping以映射 LINQ 样式。它使您可以将数据库映射与模型完全分离(无需注释)