如何在Dapper中创建具有三级深度映射的多映射查询?

时间:2016-08-09 23:13:43

标签: c# dapper

我正在尝试执行正确映射以下内容的查询:

public class A
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int BId {get; set; }
    public List<B> { get; set; }
}

public class B
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int CId { get; set; }
    public int DId { get; set; }
    public C C { get; set; }
    public D D { get; set; }
}

public class C
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class D
{
    public int Id { get; set; }
    public string Name { get; set; }
}

如何编写一个正确映射实体A的查询,其中包含填充了C和D的实体B列表?

2 个答案:

答案 0 :(得分:1)

您想在此处执行两个查询,以捕获A上B的一对多性质。此外,您的B可能需要在查询中返回A的引用。

var query1 = conn.Query<A>(select * from dbo.A)

var query2 = conn.Query<B,C,D,B>("select * from dbo.B...join C...join 

D",(b,c,d)=>{



     b.C = c;
        b.D = d;

return b;

        }

现在你必须将它们连接在一起。我使用linq连接和扩展来自动化它的一堆,但要点是,循环遍历每个'A'并从查询2中找到匹配的'B'。字典和列表也可能比'Where'子句更快,所以你可以写一个优化下面循环的扩展。

foreach(var a in query1){
a.Bs = query2.Where(w=>w.AId.Equals(a.Id));
}

请注意,您可以通过使用QueryMultiple返回多个记录集来减少数据库的访问(如果您的数据库支持该数据集)。

答案 1 :(得分:0)

您可以使用Drapper(建立在Dapper之上)完成对数据库的一次往返。

假设您有一组返回多个结果的SQL查询:

select * from [TableA]; 
select * from [TableB]; 
select * from [TableC]; 
select * from [TableD]

...每个结果都有某种形式的标识符/外键给其他人,你可能会建立一个如下所示的存储库:

public class Repository : IRepository
{
    // IDbCommander is a Drapper construct.
    private readonly IDbCommander _commander;

    public Repository(IDbCommander commander)
    {
        _commander = commander;
    }

    public IEnumerable<A> RetrieveAll()
    {
        // execute the multiple queries and 
        // pass control to a mapping function.
        return _commander.Query(Map.Results);
    }

    private static class Map
    {
        internal static Func<IEnumerable<A>,
                            IEnumerable<B>,
                            IEnumerable<C>,
                            IEnumerable<C>,
                            IEnumerable<A>> Results = (collectionA, collectionB, collectionC, collectionD) => 
        {
            // map C and D to B based on their Id's
            collectionB.C = collectionC.SingleOrDefault(c => c.Id == b.Id);
            collectionB.D = collectionD.SingleOrDefault(d => d.Id == b.Id);

            // now map B to A.
            collectionA.B = collectionB.Where(b => b.Id == a.Id).ToList();
            return collectionA;
        }
    }
}

从内存中键入的示例因此语法可能稍微偏离但你得到了要点。

我同意BlackjacetMack你应该在结果中加入某种形式的分页(在Drapper中也支持)。