使用列表中的列表将 Dapper 多映射结果聚合到对象

Aggregating Dapper Multi Mapping Results To Object with List Within a List

我对 dapper 比较陌生,并试图聚合它的数据 returns。我试图弄清楚如何将结果映射到具有列表 属性 的对象,该列表也具有列表 属性.

我的对象:

public class Employee()
{
    public string Id { get; set; }
    public string Name { get; set; } 
    public List<Employement> Employments { get; set; }
}

public class Employment()
{
    public string CompanyId { get; set; }
    public string Company { get; set; }
    public DateTime HireDate { get; set; }
    public List<JobInfo> JobInfo { get; set; }
}

public class JobInfo()
{
    public string JobTitle { get; set; }
    public string Salary { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime? EndDate { get; set; }
}

我的方法:

var historyDictionary = new Dictionary<string, Employee>();

var results = await connection.QueryAsync<Employee, Employment, JobInfo, Employee>(
    sqlQuery,
    (e, em, ji) => {
        Employee emp;
        if (!lookup.TryGetValue(e.Id, out emp))
                historyDictionary .Add(e.Id, emp = e);

        if (emp.Employments == null)
                emp.Employments = new List<Employment> { em };
        else if (!emp.Employments.Exists(ec => ec.CompanyId == em.CompanyId))
                emp.Employments.Add(em);

        //map JobInfo

        return emp;          
    }, SplitOn: "Id"
);

我似乎无法全神贯注地映射 JobInfo。我知道我不能只做我在映射 Employment 时正在做的事情,因为它是 Employee 下的列表并且做 Employee.Employments 不会让我直接访问 JobInfo 对象,所以我假设我需要使用 linq

这就是我想要得到的

Id,
Name,
new List<Employment> {
    new Employment1 {
        CompanyId,
        CompanyName,
        HireDate,
        new List<JobInfo> {
            new JobInfo {
                JobTitle1,
                Salary,
                StartDate,
                EndDate
            },
            new JobInfo {
                JobTitle2,
                Salary,
                StartDate,
                EndDate
            }
        }
    }
    new Employment2 {
        CompanyId,
        CompanyName,
        HireDate,
        new List<JobInfo> {
            new JobInfo {
                JobTitle1,
                Salary,
                StartDate,
                EndDate
            }
        }
    }
}

并希望确保将正确的工作信息映射到正确的工作

另外,我想充分了解dapper mapping,是不是每行数据映射sql个数据?

样本sql数据

Id      Name        CompanyId   Company     HireDate    JobTitle    Salary      StartDate       EndDate
001     employee1   123         company1    01-01-2010  job1        12345       01-01-2010      01-01-2012
001     employee1   123         company1    01-01-2010  job2        23456       01-01-2012      02-02-2015      
001     employee1   456         company2    01-01-2016  job3        34567       03-03-2016      null
002     employee2   123         company1    02-02-2015  job4        23789       02-02-2015      null

首先,你的Dapper查询不太正确:当使用multi-mapping时,对象在结果集中垂直分割(一些列用于父对象,一些用于子),并且您需要提供 split 点,即每个对象的起始列。

然后您将每个对象映射到其嵌套位置,具体取决于它是否存在。对于另一层嵌套,您只需获取上一层并再次查找。

var historyDictionary = new Dictionary<string, Employee>();

var results = await connection.QueryAsync<Employee, Employment, JobInfo, Employee>(
    sqlQuery,
    (e, em, ji) => {
        if (!lookup.TryGetValue(e.Id, out var emp))
            historyDictionary.Add(e.Id, emp = e);

        if (emp.Employments == null)
            emp.Employments = new List<Employment> { em };
        else
        {
            em2 = emp.Employments.Find(ec => ec.CompanyId == em.CompanyId);
            if(em2 == null)
                emp.Employments.Add(em);
            else
                em = em2;
        }

        em.JobInfo = em.JobInfo ?? new List<JobInfo>();
        em.JobInfo.Add(ji);

        return emp;          
    }, SplitOn: nameof(Employment.CompanyId) + "," + nameof(JobInfo.JobTitle)
);

您可以通过在构造函数中分配默认 List 对象来稍微简化逻辑。通常我会使用 Dictionary 而不是 List,这样查找也更简单:

var historyDictionary = new Dictionary<string, Employee>();

var results = await connection.QueryAsync<Employee, Employment, JobInfo, Employee>(
    sqlQuery,
    (e, em, ji) => {
        if (!lookup.TryGetValue(e.Id, out var em2))
            historyDictionary.Add(e.Id, em2 = e);

        if (!emp.Employments.TryGetValue(em.CompanyId, out var em2))
            emp.Employments.Add(em.CompanyId, em2 = em);

        em2.JobInfo.Add(ji);

        return emp;          
    }, SplitOn: nameof(Employment.CompanyId) + "," + nameof(JobInfo.JobTitle)
);

您还应该查看 QueryMultiple,其中有多个 SELECT 查询,您可以自己映射它们。这可以防止在某些情况下出现大量重复行。