2016-07-04 18 views
0

Ich habe ein Place-Objekt.Dapper.net - wie man viele zu viele Beziehungen in einem einzigen Befehl abbildet

Es kann viele Tags damit verbunden haben.

Tags können mit vielen Orten verknüpft werden.

(Obwohl dies eine Beziehung viele zu viele ist - ich denke konzeptionell kann es auch eine eins zu viele sein - eine Sammlung von Objekten - mit jedem Objekt enthält eine Sammlung von Objekten).

Jeder Platz Objekt verfügt über eine Liste Sammlung mit ihm verbunden:

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, die von vielen zu vielen Beziehung erforderlichen Daten wählt:

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 

Kann ich all dies in einem einzigen Dapper Karte Befehl (oder zumindest nicht n + 1 Befehle)? Die Github-Dokumentation deckt eine zu viele Beziehungen ab - aber nicht viele zu viele.

(Der Grund, warum ich dies tun muss - ist, weil ich ein Raster aller Orte ausgeben möchte, und ich möchte eine Spalte eine kommagetrennte Liste von Tags (Ich werde einen Helper, der eine Sammlung von Tags dauert erstellen ., und gibt eine durch Kommata getrennte Zeichenfolge)

ich habe eine ähnliche Frage gesehen, wo Slapper.AutoMapper empfohlen:

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

würde ich lieber vermeiden, mit zusätzlichen Bibliotheken wenn möglich - aber ich denke, es kann sein, hier erforderlich?

Was ist der beste Weg, dies zu erreichen?

Antwort

1

I ausgegeben werden soll ein Raster von allen Orten, und ich möchte eine Spalte ein durch Kommata getrennte Liste von Tags

werden, da Sie alle Orte wollen, müssen Sie eine LEFT JOIN anstelle von innerem Join, um alle Orte und zugehörige Tags zu erhalten.

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"; 

Diese Abfrage wird ein Ergebnis mit 3 Spalten geben: Id, Name und TagName. Ich würde ein einfaches DTO für den Resultset-Datensatz erstellen.

Verwenden Sie nun Dapper, um die Abfrage auszuführen und das Ergebnis der PostTagDto-Auflistung zuzuordnen. Dann gruppieren Sie das Ergebnis nach 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() 
                }); 
} 

Auch, wenn Sie den Tags-Objekttyp List<Tag>-IEnumerable<Tag> ändern, können Sie den ToList() Anruf in dem LINQ Ausdruck vermeiden.

Jetzt in Ihrem UI können Sie String.Join Methode verwenden, die durch Kommata getrennte Liste von Variablen zu zeigen,

@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>