サーチ…


構文

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

パラメーター

パラメータ詳細
cnn あなたのデータベース接続は既にオープンしている必要があります。
SQL 実行するコマンド。
タイプレコードセット内の型の配列。
地図返された結果の構築を処理するFunc<>
パラメータパラメータを抽出するオブジェクト。
トランザクションこのクエリがある場合はそのトランザクションの一部であるトランザクション。
緩衝問合せの結果をバッファリングするかどうか。これは省略可能なパラメータであり、デフォルトはtrueです。 bufferedがtrueの場合、結果はList<T>バッファされ、複数の列挙で安全なIEnumerable<T>として返されます。 bufferedがfalseの場合、sql接続は読み込みが終了するまで開かれたままになり、メモリー内の一度の行を処理できます。複数の列挙により、データベースへの追加の接続が生成されます。バッファリングされた偽のメモリ使用量を削減するための非常に効率的ですが、あなたはレコードだけの非常に小さな断片を維持するならば、それは持って返さかなりのパフォーマンス・オーバーヘッドを熱心に結果セットを実体化に比べて。最後に、多数のバッファリングされていないSQL接続が並行している場合は、接続プールが不要になると、接続が使用可能になるまでブロック要求が発生することを考慮する必要があります。
splitOn フィールドは、2番目のオブジェクトを分割して読み込む必要があります(デフォルト:id)。レコードに複数の型が含まれている場合は、コンマで区切られたリストにすることができます。
commandTimeout コマンド実行タイムアウトまでの秒数。
commandType それはストアドプロシージャかバッチですか?

シンプルなマルチテーブルマッピング

Personクラスを生成する必要がある残りの騎手のクエリがあるとします。

うまれたレジデンス
ダニエルデネット 1942 アメリカ合衆国
サムハリス 1967 アメリカ合衆国
リチャード・ドーキンス 1941 イギリス
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; }
}

返されたインスタンスを作成するために使用できるFunc<>をとるオーバーロードQuery<>を使用して、 Func<>クラスとResidenceプロパティをCountryのインスタンスにFunc<>ことができます。 Func<>は最大7つの入力タイプをとり、最終総称引数は常に戻り値の型です。

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

splitOn: "Residence"引数の使用に注意してください。この引数は、次のクラスタイプ(この場合はCountry )の第1列です。 Dapperは自動的に分割するIdという列を探しますが、見つからずsplitOnが指定されていない場合は、有用なメッセージが表示されてSystem.ArgumentExceptionがスローされます。したがって、オプションですが、通常はsplitOn値を指定するsplitOnます。

1対多マッピング

1対多の関係を含むより複雑な例を見てみましょう。クエリに重複データが含まれる複数の行が含まれるようになりました。これを処理する必要があります。これはクロージャーで検索します。

サンプルクラスと同様にクエリがわずかに変更されます。

イドうまれた CountryId 国名 BookId BookName
1 ダニエルデネット 1942 1 アメリカ合衆国 1 ブレインストーム
1 ダニエルデネット 1942 1 アメリカ合衆国 2 エルボールーム
2 サムハリス 1967 1 アメリカ合衆国 3 モラルの風景
2 サムハリス 1967 1 アメリカ合衆国 4 目を覚ます:宗教のない霊性の指針
3 リチャード・ドーキンス 1941 2 イギリス 5 現実の魔法:どのように私たちが知っているか本当に真実
3 リチャード・ドーキンス 1941 2 イギリス 6 不思議のための食欲:科学者の製作
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; }
}

remainingHorsemen預言者には、完全にマテリアライズされた人物オブジェクトのインスタンスが取り込まれます。クエリ結果の各行に対して、lambda引数で定義された型のインスタンスのマップされた値が渡され、これをどのように処理するかはあなた次第です。

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

splitOn引数が、次の型の最初の列のカンマ区切りリストであることに注意してください。

7種類以上のマッピング

マッピングするタイプの数が、構築を行うFunc <>によって提供される7を超えることがあります。

Query<>にジェネリック型引数の入力を使用する代わりに、配列としてマッピングする型と、それに続くマッピング関数を提供します。初期のマニュアル設定や値のキャスト以外は、残りの機能は変更されません。

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

カスタムマッピング

クエリの列名がクラスと一致しない場合は、型のマッピングを設定できます。この例は、カスタムマッピングと同様にSystem.Data.Linq.Mapping.ColumnAttributeを使用したマッピングを示しています。

マッピングは、タイプごとに1回だけ設定する必要があるため、アプリケーションの起動時に設定するか、または1回だけ初期化されるように設定します。

One-to-Manyの例と同じクエリを再度仮定し、クラスをより良い名前にリファクタリングします。

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

BookColumnAttribute依存しない方法に注意してください。ただし、 ifステートメントを維持する必要があります

今度はこのマッピングコードをアプリケーションのどこかに置いて、一度だけ実行します:

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

その後、以前のQuery<>例のいずれかを使用してクエリが実行されます。

この回答には、マッピングを追加する簡単な方法が示されています



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow