【发布时间】:2014-01-06 13:56:59
【问题描述】:
我尝试将我的 Id 字段与列属性映射,但由于某种原因,这似乎不起作用,我不知道为什么。我设置了一个测试项目来展示我正在尝试的内容。
首先,我得到了我的 2 个实体:
实体表1
using System.Data.Linq.Mapping;
namespace DapperTestProj
{
public class Table1
{
[Column(Name = "Table1Id")]
public int Id { get; set; }
public string Column1 { get; set; }
public string Column2 { get; set; }
public Table2 Table2 { get; set; }
public Table1()
{
Table2 = new Table2();
}
}
}
和实体表2
using System.Data.Linq.Mapping;
namespace DapperTestProj
{
public class Table2
{
[Column(Name = "Table2Id")]
public int Id { get; set; }
public string Column3 { get; set; }
public string Column4 { get; set; }
}
}
在我的数据库中,我有 2 个表,也称为 Table1 和 Table2。除了 Table1 有一个名为 Table2Id 的列并且 Table1.Table2Id 和 Table2.Id 之间还有一个外键之外,这两个表的列名称都与实体相同。
此外,两个表中各有 1 条记录,并且它们的 ID 都为 2。
接下来我尝试使用 dapper 执行查询,它应该返回 Table1 类型的对象。这可行,但属性 Table1.Id 和 Table1.Table2.Id 都保持为 0(默认整数)。我希望列属性会映射 Id 字段,但显然这不会发生。
这是我在代码中执行的查询和映射:
private Table1 TestMethod(IDbConnection connection)
{
var result = connection.Query<Table1, Table2, Table1>(
@"SELECT
T1.Id as Table1Id,
T1.Column1 as Column1,
T1.Column2 as Column2,
T2.Id as Table2Id,
T2.Column3 as Column3,
T2.Column4 as Column4
FROM Table1 T1
INNER JOIN Table2 T2 ON T1.Table2Id = T2.Id",
(table1, table2) =>
{
table1.Table2 = table2;
return table1;
},
splitOn: "Table2Id"
).SingleOrDefault();
return result;
}
现在我可以将实体中的两个 Id 属性字段重命名为 Table1Id 和 Table2Id,但我更喜欢 Id 而不是因为更多的逻辑代码,如 Table1.Id 而不是 Table1.Table1Id。所以我想知道,这里有没有可能是我想要的,如果是的话,怎么做?
编辑:
我发现了这个话题: Manually Map column names with class properties
通过 Kaleb Pederson 第一篇文章中的代码,可以在需要时使用 FallBackTypeMapper 类和 ColumnAttributeTypeMapper 类的属性。所需要的只是将所需的类添加到类型映射中:
SqlMapper.SetTypeMap(typeof(Table1), new ColumnAttributeTypeMapper<Table1>());
SqlMapper.SetTypeMap(typeof(Table2), new ColumnAttributeTypeMapper<Table2>());
但是对于许多实体,此列表会变得很长。此外,您需要手动将每个类添加到列表中,我想知道这是否可以通过反射自动完成,更加通用。我找到了一个可以获取所有类型的代码片段:
const string @namespace = "DapperTestProj.Entities";
var types = from type in Assembly.GetExecutingAssembly().GetTypes()
where type.IsClass && type.Namespace == @namespace
select type;
循环遍历所有类型,我可以做到这一点,我现在唯一的问题是我现在需要或需要在问号所在的地方放置什么代码片段?
typeList.ToList().ForEach(type => SqlMapper.SetTypeMap(type,
new ColumnAttributeTypeMapper</*???*/>()));
编辑:
经过更多搜索,我找到了我最后一个问题的解决方案:
typeList.ToList().ForEach(type =>
{
var mapper = (SqlMapper.ITypeMap)Activator.CreateInstance(
typeof(ColumnAttributeTypeMapper<>)
.MakeGenericType(type));
SqlMapper.SetTypeMap(type, mapper);
});
【问题讨论】:
-
好吧,我也尝试了 System.ComponentModel.DataAnnotations 属性中的数据注释,但这些也不起作用。我在想,也许 Dapper 正在使用这些,但我想我错了。那么我的问题是,那我应该使用哪些属性呢?
-
如果你使用 Dapper,你应该在查询和类之间有一个匹配。所以代替 T1.Id 作为 Table1Id
-
似乎可以(ab)使用 Linq to SQL 属性。我更新了我的第一篇文章,展示了如何。我在获取泛型类型时遇到了一个问题。
-
记录在案,关于添加此功能的讨论已有一年之久:github.com/StackExchange/Dapper/issues/722
标签: c# dapper system.reflection