Zoeken…


Syntaxis

  • 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)

parameters

Parameter Details
cnn Uw databaseverbinding, die al open moet zijn.
sql Commando om uit te voeren.
types Array van typen in de recordset.
kaart Func<> die de constructie van het retourresultaat afhandelt.
param Object om parameters uit te halen.
transactie Transactie waarvan deze zoekopdracht deel uitmaakt, indien aanwezig.
gebufferde Of de resultaten van de query al dan niet moeten worden opgeslagen. Dit is een optionele parameter met de standaardwaarde waar. Wanneer gebufferd waar is, worden de resultaten gebufferd in een List<T> en vervolgens geretourneerd als een IEnumerable<T> die veilig is voor meerdere opsommingen. Wanneer gebufferd onwaar is, wordt de sql-verbinding opengehouden totdat u klaar bent met lezen, zodat u een enkele rij tegelijk in het geheugen kunt verwerken. Meerdere opsommingen zorgen voor extra verbindingen met de database. Hoewel gebufferde false zeer efficiënt is voor het verminderen van geheugengebruik, als u slechts zeer kleine fragmenten van de geretourneerde records bijhoudt, heeft het een aanzienlijke prestatie-overhead in vergelijking met het gretig materialiseren van de resultaatset. Ten slotte, als u meerdere gelijktijdige niet-gebufferde sql-verbindingen heeft, moet u overwegen om de pool van de verbinding te verhinderen waardoor verzoeken worden geblokkeerd totdat verbindingen beschikbaar komen.
verdeeld over Het veld waarvan we het tweede object moeten splitsen en lezen (standaard: id). Dit kan een door komma's gescheiden lijst zijn als er meer dan 1 type in een record voorkomt.
CommandTimeout Aantal seconden vóór de time-out van de opdrachtuitvoering.
CommandType Is het een opgeslagen procedure of een batch?

Eenvoudige toewijzing van meerdere tabellen

Stel dat we een vraag hebben over de resterende ruiters die een Person-klasse moeten invullen.

Naam Geboren residentie
Daniel Dennett 1942 Verenigde Staten van Amerika
Sam Harris 1967 Verenigde Staten van Amerika
Richard Dawkins 1941 Verenigd Koninkrijk
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; }
}

We kunnen de personklasse en de eigenschap Residence vullen met een instantie van Country met een overload Query<> waarvoor een Func<> die kan worden gebruikt om de geretourneerde instantie samen te stellen. De functie Func<> kan tot 7 Func<> aannemen, waarbij het laatste generieke argument altijd het retourtype is.

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

Let op het gebruik van het splitOn: "Residence" , dat de 1e kolom is van het volgende te typen klassentype (in dit geval Country ). Dapper automatisch op zoek naar een kolom met de naam Id te splitsen op, maar als het niet een te vinden en splitOn is niet voorzien van een System.ArgumentException zal worden gegooid met een nuttig bericht. Dus hoewel het optioneel is, moet u meestal een splitOn waarde splitOn .

Eén-op-veel-toewijzing

Laten we eens kijken naar een meer complex voorbeeld met een één-op-veel-relatie. Onze zoekopdracht bevat nu meerdere rijen met dubbele gegevens en we moeten dit afhandelen. We doen dit met een opzoeking in een afsluiting.

De query verandert enigszins, net als de voorbeeldklassen.

ID kaart Naam Geboren countryID Naam van het land BookID BookName
1 Daniel Dennett 1942 1 Verenigde Staten van Amerika 1 brainstorms
1 Daniel Dennett 1942 1 Verenigde Staten van Amerika 2 Elleboogruimte
2 Sam Harris 1967 1 Verenigde Staten van Amerika 3 Het morele landschap
2 Sam Harris 1967 1 Verenigde Staten van Amerika 4 Wakker worden: een gids voor spiritualiteit zonder religie
3 Richard Dawkins 1941 2 Verenigd Koninkrijk 5 De magie van de realiteit: hoe we weten wat echt waar is
3 Richard Dawkins 1941 2 Verenigd Koninkrijk 6 Appetite for Wonder: The Making of a Scientist
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; }
}

In het remainingHorsemen woordenboek remainingHorsemen ruiters gevuld met volledig gematerialiseerde exemplaren van de persoonsobjecten. Voor elke rij van het queryresultaat worden de toegewezen waarden van instanties van de typen die zijn gedefinieerd in de lambda-argumenten doorgegeven en het is aan u hoe u hiermee omgaat.

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

Merk op hoe het argument splitOn een door komma's gescheiden lijst is van de eerste kolommen van het volgende type.

Meer dan 7 typen in kaart brengen

Soms is het aantal typen dat u in kaart brengt groter dan de 7 die worden geleverd door de Func <> die de constructie uitvoert.

In plaats van Query<> met de generieke invoer voor argumentargumenten, bieden we de typen waarnaar moet worden toegewezen als een array, gevolgd door de toewijzingsfunctie. Afgezien van de initiële handmatige instelling en het casten van de waarden, verandert de rest van de functie niet.

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

Aangepaste toewijzingen

Als de namen van de querykolommen niet overeenkomen met uw klassen, kunt u toewijzingen instellen voor typen. Dit voorbeeld demonstreert kaarten met behulp van System.Data.Linq.Mapping.ColumnAttribute en een aangepaste toewijzing.

De toewijzingen hoeven slechts eenmaal per type te worden ingesteld, dus stel ze in bij het opstarten van de toepassing of ergens anders dat ze slechts eenmaal worden geïnitialiseerd.

Uitgaande van dezelfde query als het One-to-many-voorbeeld opnieuw en de klassen gerefacteerd naar betere namen zoals dit:

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

Merk op dat Book niet afhankelijk is van ColumnAttribute maar dat we de if instructie moeten behouden

Plaats deze toewijzingscode nu ergens in uw toepassing waar deze slechts eenmaal wordt uitgevoerd:

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

Vervolgens wordt de query uitgevoerd met behulp van een van de vorige voorbeelden Query<> .

Een eenvoudigere manier om de toewijzingen toe te voegen wordt in dit antwoord getoond.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow