我正在尝试使用 Dapper 以一对多关系映射对象。假设一个数据库包含一个 Departments 表和一个 People 表。 People 表有一个 DepartmentId 列,用于创建人员和部门之间的关系。每个人只能在一个部门。
我的代码中有以下模型:
public class PersonModel
{
public int Id {get; set;}
public string FullName {get; set;}
public DepartmentModel Department {get; set;}
}
public class DepartmentModel
{
public int Id {get; set;}
public string Name {get; set;}
}
我想使用 Dapper 来获取 People 并将它们存储在包含 Departments 属性的对象中。 SplitOn 可以做到这一点,如下所示:
public Task<IEnumberable<PersonModel>> GetPeople<PersonModel>(string connectionString)
{
using var connection = new SqlConnection(connectionString);
var query = "Select People.Id, People.FullName, Department.Name FROM People LEFT JOIN Departments ON People.Id = Departments.Id";
return await connection.QueryAsync<PersonModel, DepartmentModel, PersonModel>(query, (person, department) => {
person.Department = department;
return person;
},
splitOn: "Id" );
}
实际问题
到目前为止一切顺利。我现在想要的是使用泛型将其转换为可重用的方法,但我陷入困境,因为我无法使用泛型进行赋值
person.Department = department
,因为 .Department
是我不知道的属性。我不能简单地使用department
。我也尝试过model.typeof(TSubModel)
(见下文)。有什么办法可以实现这一点吗?失败的代码是:
public Task<IEnumberable<TModel>> GetPeople<TModel, TSubModel>(string connectionString, string query)
{
using var connection = new SqlConnection(connectionString);
return await connection.QueryAsync<TModel, TSubModel, TModel>(query, (model, subModel) => {
model.subModel= subModel; // <-- obviously model.subModel fails and so does model.typeof(TSubModel).
return model;
},
splitOn: "Id" );
}
PS,OP 回答了一个类似的问题,但没有使用 SplitOn 这里(SO 问题)
除非有某种方法可以确定通过反射设置哪个属性,否则这是不可能的。
您可以从外部穿过
Action<TModel, TSubModel>
lambda。
public Task<IEnumberable<TModel>> GetPeople<TModel, TSubModel>(string connectionString, string query, Action<TModel, TSubModel> splitOnAction)
{
using var connection = new SqlConnection(connectionString);
return await connection.QueryAsync<TModel, TSubModel, TModel>(query, (model, subModel) => {
splitOnAction(model, subModel);
return model;
},
splitOn: "Id" );
}
和
var results = await GetPeople<PersonModel, DepartmentModel>(connString, query,
(person, dep) => person.Deparmtent = dep
);
但目前我不确定直接使用 Dapper 能带来什么好处。最重要的是,您无法传递查询参数或
QueryAsync
所采用的任何其他参数。
我建议你重新考虑尝试“通用”地执行此操作,因为 Dapper 已经为你提供了这一点。