Sök…


Syntax

  • public static IEnumerable<TReturn> Query<TFirst, TSecond, TReturn>( this IDbConnection cnn, string sql, Func<TFirst, TSecond, TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null)
  • public static IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null)
  • public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string sql, Type[] types, Func<object[], TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null)

parametrar

Parameter detaljer
cnn Din databasanslutning, som redan måste vara öppen.
sQL Kommando att utföra.
typer Array av typer i postuppsättningen.
Karta Func<> som hanterar konstruktionen av returresultatet.
param Objekt att extrahera parametrar från.
transaktion Transaktion som denna fråga är en del av, om någon.
buffrad Huruvida buffertläsning av resultaten från frågan ska göras eller inte. Detta är en valfri parameter med standardinställningen sant. När buffrat är sant buffras resultaten till en List<T> och returneras sedan som ett IEnumerable<T> som är säkert för flera uppräkning. När buffrat är felaktigt hålls sql-anslutningen öppen tills du är klar med läsningen så att du kan behandla en enda rad samtidigt i minnet. Flera uppräkningar kommer att leda till ytterligare anslutningar till databasen. Även om buffrad falsk är mycket effektiv för att minska minnesanvändningen om du bara behåller mycket små fragment av de poster som återlämnats har den en betydande prestanda jämfört med ivrigt materialisering av resultatuppsättningen. Slutligen, om du har många samtidiga obuffrade sql-anslutningar, måste du överväga anslutning till poolen svält vilket orsakar förfrågningar om att blockera tills anslutningarna blir tillgängliga.
dela på Fältet vi ska dela och läsa det andra objektet från (standard: id). Detta kan vara en kommaavgränsad lista när mer än 1 typ finns i en post.
commandTimeout Antal sekunder innan timeout för kommandokörning.
Command Är det en lagrad proc eller en batch?

Enkel kartläggning av flera bord

Låt oss säga att vi har en fråga om de återstående ryttarna som behöver fylla en personklass.

namn Född Bostad
Daniel Dennett 1942 Amerikas förenta stater
Sam Harris 1967 Amerikas förenta stater
Richard Dawkins 1941 Storbritannien
public class Person
{
    public string Name { get; set; }
    public int Born { get; set; }
    public Country Residience { get; set; }
}

public class Country
{
    public string Residence { get; set; }
}

Vi kan fylla såväl personklassen som bostadsfastigheten med en instans av land med hjälp av en överbelastningsfråga Query<> som tar en Func<> som kan användas för att komponera den returnerade instansen. Func<> kan ta upp till sju ingångstyper med det slutliga generiska argumentet som alltid är returtypen.

var sql = @"SELECT 'Daniel Dennett' AS Name, 1942 AS Born, 'United States of America' AS Residence
UNION ALL SELECT 'Sam Harris' AS Name, 1967 AS Born, 'United States of America' AS Residence
UNION ALL SELECT 'Richard Dawkins' AS Name, 1941 AS Born, 'United Kingdom' AS Residence";

var result = connection.Query<Person, Country, Person>(sql, (person, country) => {
        if(country == null)
        {
            country = new Country { Residence = "" };
        }
        person.Residience = country;
        return person;
    }, 
    splitOn: "Residence");

Notera användningen av splitOn: "Residence" -argumentet som är den första kolumnen i nästa klasstyp som ska fyllas (i detta fall Country ). Dapper letar automatiskt efter en kolumn som heter Id att dela på men om den inte hittar en och splitOn inte tillhandahålls ett System.ArgumentException kastas med ett användbart meddelande. Så även om det är valfritt måste du vanligtvis splitOn ett splitOn värde.

En-till-många-kartläggning

Låt oss titta på ett mer komplext exempel som innehåller en en-till-många-relation. Vår fråga kommer nu att innehålla flera rader som innehåller duplicerade data och vi måste hantera detta. Vi gör detta med en uppslagning i en stängning.

Frågan ändras något liksom exempelklasserna.

Id namn Född CountryId Lands namn BookId BookName
1 Daniel Dennett 1942 1 Amerikas förenta stater 1 brainstorming
1 Daniel Dennett 1942 1 Amerikas förenta stater 2 Svängrum
2 Sam Harris 1967 1 Amerikas förenta stater 3 Det moraliska landskapet
2 Sam Harris 1967 1 Amerikas förenta stater 4 Vakna upp: En guide till andlighet utan religion
3 Richard Dawkins 1941 2 Storbritannien 5 Verklighetens magi: hur vi vet vad som verkligen är sant
3 Richard Dawkins 1941 2 Storbritannien 6 En aptit för undring: skapandet av en forskare
public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Born { get; set; }
    public Country Residience { get; set; }
    public ICollection<Book> Books { get; set; }
}

public class Country
{
    public int CountryId { get; set; }
    public string CountryName { get; set; }
}

public class Book
{
    public int BookId { get; set; }
    public string BookName { get; set; }
}

Den remainingHorsemen ordboken remainingHorsemen kommer att fyllas med fullständigt materialiserade instanser av personobjekten. För varje rad i frågeställningen ges de mappade värdena på instanser av de typer som definieras i lambda-argumenten och det är upp till dig hur du hanterar detta.

            var sql = @"SELECT 1 AS Id, 'Daniel Dennett' AS Name, 1942 AS Born, 1 AS CountryId, 'United States of America' AS CountryName, 1 AS BookId, 'Brainstorms' AS BookName
UNION ALL SELECT 1 AS Id, 'Daniel Dennett' AS Name, 1942 AS Born, 1 AS CountryId, 'United States of America' AS CountryName, 2 AS BookId, 'Elbow Room' AS BookName
UNION ALL SELECT 2 AS Id, 'Sam Harris' AS Name, 1967 AS Born, 1 AS CountryId,  'United States of America' AS CountryName, 3 AS BookId, 'The Moral Landscape' AS BookName
UNION ALL SELECT 2 AS Id, 'Sam Harris' AS Name, 1967 AS Born, 1 AS CountryId,  'United States of America' AS CountryName, 4 AS BookId, 'Waking Up: A Guide to Spirituality Without Religion' AS BookName
UNION ALL SELECT 3 AS Id, 'Richard Dawkins' AS Name, 1941 AS Born, 2 AS CountryId,  'United Kingdom' AS CountryName, 5 AS BookId, 'The Magic of Reality: How We Know What`s Really True' AS BookName
UNION ALL SELECT 3 AS Id, 'Richard Dawkins' AS Name, 1941 AS Born, 2 AS CountryId,  'United Kingdom' AS CountryName, 6 AS BookId, 'An Appetite for Wonder: The Making of a Scientist' AS BookName";

var remainingHorsemen = new Dictionary<int, Person>();
connection.Query<Person, Country, Book, Person>(sql, (person, country, book) => {
    //person
    Person personEntity;
    //trip
    if (!remainingHorsemen.TryGetValue(person.Id, out personEntity))
    {
        remainingHorsemen.Add(person.Id, personEntity = person);
    }

    //country
    if(personEntity.Residience == null)
    {
        if (country == null)
        {
            country = new Country { CountryName = "" };
        }
        personEntity.Residience = country;
    }                    

    //books
    if(personEntity.Books == null)
    {
        personEntity.Books = new List<Book>();
    }

    if (book != null)
    {
        if (!personEntity.Books.Any(x => x.BookId == book.BookId))
        {
            personEntity.Books.Add(book);
        }
    }

    return personEntity;
}, 
splitOn: "CountryId,BookId");

Lägg märke till hur splitOn argumentet är en kommaavgränsad lista över de första kolumnerna av nästa typ.

Kartlägga mer än sju typer

Ibland överstiger antalet typer du kartlägger de 7 som tillhandahålls av Func <> som utför konstruktionen.

Istället för att använda Query<> med de generiska argumentinmatningarna kommer vi att tillhandahålla de typer som ska kartläggas som en matris, följt av mappningsfunktionen. Förutom den initiala manuella inställningen och gjutningen av värdena, ändras inte resten av funktionen.

            var sql = @"SELECT 1 AS Id, 'Daniel Dennett' AS Name, 1942 AS Born, 1 AS CountryId, 'United States of America' AS CountryName, 1 AS BookId, 'Brainstorms' AS BookName
UNION ALL SELECT 1 AS Id, 'Daniel Dennett' AS Name, 1942 AS Born, 1 AS CountryId, 'United States of America' AS CountryName, 2 AS BookId, 'Elbow Room' AS BookName
UNION ALL SELECT 2 AS Id, 'Sam Harris' AS Name, 1967 AS Born, 1 AS CountryId,  'United States of America' AS CountryName, 3 AS BookId, 'The Moral Landscape' AS BookName
UNION ALL SELECT 2 AS Id, 'Sam Harris' AS Name, 1967 AS Born, 1 AS CountryId,  'United States of America' AS CountryName, 4 AS BookId, 'Waking Up: A Guide to Spirituality Without Religion' AS BookName
UNION ALL SELECT 3 AS Id, 'Richard Dawkins' AS Name, 1941 AS Born, 2 AS CountryId,  'United Kingdom' AS CountryName, 5 AS BookId, 'The Magic of Reality: How We Know What`s Really True' AS BookName
UNION ALL SELECT 3 AS Id, 'Richard Dawkins' AS Name, 1941 AS Born, 2 AS CountryId,  'United Kingdom' AS CountryName, 6 AS BookId, 'An Appetite for Wonder: The Making of a Scientist' AS BookName";

var remainingHorsemen = new Dictionary<int, Person>();
connection.Query<Person>(sql,
    new[]
    {
        typeof(Person),
        typeof(Country),
        typeof(Book)
    }
    , obj => {

        Person person = obj[0] as Person;
        Country country = obj[1] as Country;
        Book book = obj[2] as Book;

        //person
        Person personEntity;
        //trip
        if (!remainingHorsemen.TryGetValue(person.Id, out personEntity))
        {
            remainingHorsemen.Add(person.Id, personEntity = person);
        }

        //country
        if(personEntity.Residience == null)
        {
            if (country == null)
            {
                country = new Country { CountryName = "" };
            }
            personEntity.Residience = country;
        }                    

        //books
        if(personEntity.Books == null)
        {
            personEntity.Books = new List<Book>();
        }

        if (book != null)
        {
            if (!personEntity.Books.Any(x => x.BookId == book.BookId))
            {
                personEntity.Books.Add(book);
            }
        }

        return personEntity;
},
splitOn: "CountryId,BookId");

Anpassade kartläggningar

Om namnet på frågekolumnen inte stämmer med dina klasser kan du ställa in mappningar för typer. Detta exempel visar kartläggning med System.Data.Linq.Mapping.ColumnAttribute såväl som en anpassad kartläggning.

Kartläggningarna behöver bara konfigureras en gång per typ så ställ dem in vid programstart eller någon annanstans att de bara initialiseras en gång.

Antagande samma fråga som exemplet En-till-många igen och klasserna refaktorerade mot bättre namn som så:

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Born { get; set; }
    public Country Residience { get; set; }
    public ICollection<Book> Books { get; set; }
}

public class Country
{
    [System.Data.Linq.Mapping.Column(Name = "CountryId")]
    public int Id { get; set; }

    [System.Data.Linq.Mapping.Column(Name = "CountryName")]
    public string Name { get; set; }
}

public class Book
{
    public int Id { get; set; }

    public string Name { get; set; }
}

Lägg märke till hur Book inte förlitar sig på ColumnAttribute men vi måste behålla if uttalandet

Placera nu denna kartläggningskod någonstans i din applikation där den bara körs en gång:

Dapper.SqlMapper.SetTypeMap(
    typeof(Country),
    new CustomPropertyTypeMap(
        typeof(Country),
        (type, columnName) =>
            type.GetProperties().FirstOrDefault(prop =>
                prop.GetCustomAttributes(false)
                    .OfType<System.Data.Linq.Mapping.ColumnAttribute>()
                    .Any(attr => attr.Name == columnName)))
);


var bookMap = new CustomPropertyTypeMap(
    typeof(Book),
    (type, columnName) =>
    {
        if(columnName == "BookId")
        {
            return type.GetProperty("Id");
        }

        if (columnName == "BookName")
        {
            return type.GetProperty("Name");
        }

        throw new InvalidOperationException($"No matching mapping for {columnName}");
    }        
);
Dapper.SqlMapper.SetTypeMap(typeof(Book), bookMap);

Sedan körs frågan med hjälp av något av de tidigare Query<> exemplen.

Ett enklare sätt att lägga till mappningarna visas i det här svaret .



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow