Dapper.net - 如何在单个命令中映射多对多的关系

时间:2016-07-04 16:48:42

标签: asp.net-mvc orm asp.net-mvc-5 dapper

我有一个Place对象。

它可以有许多与之关联的标签。

标签可以与多个地方相关联。

(虽然这是一个多对多的关系 - 我想在概念上它也可能是一对多 - 一组对象 - 每个对象都包含一组对象。)

每个Place对象都有一个与之关联的List集合:

public class Place
{
    public Guid Id { get; set; }
    public string PlaceName { get; set; }
    ...
    public List<Tag> Tags { get; set; }
}

public class Tag
{
    public Guid Id { get; set; }
    public string TagName { get; set; }
}

从多对多关系中选择所需数据的SQL:

select * from place p
inner join tagplace tp on tp.placeid = p.id 
inner join tag t on t.id = tp.tagid
order by placename

我可以在一个Dapper命令中映射所有这些(或者至少不是n + 1个命令)吗? Github文档涵盖了一对多的关系 - 但不是很多。

(我需要这样做的原因 - 是因为我想输出所有地方的网格,我希望一列是逗号分隔的标签列表(我将创建一个带有标签集合的Helper)输出以逗号分隔的字符串)。

我看到了一个类似的问题,建议使用Slapper.AutoMapper:

How do I write one to many query in Dapper.Net?

如果可能的话,我宁愿避免使用额外的库 - 但我想这里可能需要它?

最好的办法是什么?

1 个答案:

答案 0 :(得分:1)

  

我想输出所有地方的网格,我希望一列成为一个   逗号分隔的标签列表

由于你想要所有的地方,你需要使用LEFT JOIN而不是内连接来获取所有的地方及其相关的标签。

var query = @"select p.Id,p.Name,t.TagName from place p
              leftjoin tagplace tp on tp.placeid = p.id 
              left join tag t on t.id = tp.tagid
              order by placename";

此查询将为结果集提供3列:Id,Name和TagName。我会为结果集记录创建一个简单的DTO。

internal class PlaceTagDto
{
   public Guid Id { internal set;get;}
   public string Name { internal set;get;}
   public string TagName { internal set; get }
}

现在使用Dapper执行查询并将结果映射到PostTagDto集合。然后按TagName对结果进行分组。

using(var c=new SqlConnecction("YourConnectionString"))
{
  var r=cn.Query<PlaceTagDto>(query);
  var grouped=r.GroupBy(s => s.Id, i => i,
                    (k, groupdPlaces) => new Place {
                               Id = k, 
                               PlaceName = groupdPlaces.First().Name,
                               Tags = groupdPlaces.Where(y=>y.TagID!=null)
                                                  .Select(t=>new Tag
                                                                 { 
                                                                   TagName = t.TagName
                                                                 }).ToList() 
                                                   });
}

此外,如果您将Tags属性类型从List<Tag>更改为IEnumerable<Tag>,则可以避免LINQ表达式中的ToList()调用。

现在,在您的用户界面中,您可以使用String.Join方法显示以逗号分隔的标记列表,

@model IEnumerable<Place>
<table>
@foreach(var p in Model)
{
  <tr>
      <td>@p.Name</td>
      <td>
          @String.Join(",",p.Tags.Select(s=>s.TagName))
      </td>
   </tr>
}
</table>