129

Dapper のマルチマッピング機能を使用して、ProductItems と関連する Customers のリストを返そうとしています。

[Table("Product")]
public class ProductItem
{
    public decimal ProductID { get; set; }        
    public string ProductName { get; set; }
    public string AccountOpened { get; set; }
    public Customer Customer { get; set; }
} 

public class Customer
{
    public decimal CustomerId { get; set; }
    public string CustomerName { get; set; }
}

私のダッパーコード:

var sql = @"select * from Product p 
            inner join Customer c on p.CustomerId = c.CustomerId 
            order by p.ProductName";

var data = con.Query<ProductItem, Customer, ProductItem>(
    sql,
    (productItem, customer) => {
        productItem.Customer = customer;
        return productItem;
    },
    splitOn: "CustomerId,CustomerName"
);

これは正常に機能しますが、すべての顧客のプロパティを返すには、完全な列リストを「splitOn」パラメーターに追加する必要があるようです。「CustomerName」を追加しないと、null が返されます。マルチマッピング機能のコア機能を誤解していますか? 毎回列名の完全なリストを追加する必要はありません。

4

7 に答える 7

222

正常に動作するテストを実行しました:

var sql = "select cast(1 as decimal) ProductId, 'a' ProductName, 'x' AccountOpened, cast(1 as decimal) CustomerId, 'name' CustomerName";

var item = connection.Query<ProductItem, Customer, ProductItem>(sql,
    (p, c) => { p.Customer = c; return p; }, splitOn: "CustomerId").First();

item.Customer.CustomerId.IsEqualTo(1);

splitOn パラメータを分割ポイントとして指定する必要があります。デフォルトは Id です。複数の分割ポイントがある場合は、それらをカンマ区切りのリストに追加する必要があります。

レコードセットが次のようになっているとします。

製品 ID | 製品名 | 口座開設 | 顧客 ID | 顧客名
------------------------------------------------------ ----------------------- --------------

Dapper は、列をこの順序で 2 つのオブジェクトに分割する方法を知る必要があります。ざっと見てみると、Customer が列から始まっていることがわかりCustomerIdますsplitOn: CustomerId

基になるテーブルの列の順序が何らかの理由で反転されている場合、ここで大きな注意点があります。

製品 ID | 製品名 | 口座開設 | 顧客名 | 顧客ID  
------------------------------------------------------ ----------------------- --------------

splitOn: CustomerIdnull の顧客名になります。

分割ポイントとして指定するCustomerId,CustomerNameと、dapper は、結果セットを 3 つのオブジェクトに分割しようとしていると想定します。CustomerId1 番目は先頭から、2 番目は から、3番目は から始まりCustomerNameます。

于 2011-09-20T00:50:57.750 に答える
4

もう1つ注意点があります。CustomerId フィールドが null の場合 (通常、左結合のクエリで)、Dapper は Customer = null で ProductItem を作成します。上記の例では:

var sql = "select cast(1 as decimal) ProductId, 'a' ProductName, 'x' AccountOpened, cast(null as decimal) CustomerId, 'n' CustomerName";
var item = connection.Query<ProductItem, Customer, ProductItem>(sql, (p, c) => { p.Customer = c; return p; }, splitOn: "CustomerId").First();
Debug.Assert(item.Customer == null); 

さらにもう 1 つの警告/トラップ。splitOn で指定されたフィールドをマップせず、そのフィールドに null が含まれている場合、Dapper は関連オブジェクト (この場合は Customer) を作成して入力します。このクラスを前の SQL で使用する方法を示すには、次のようにします。

public class Customer
{
    //public decimal CustomerId { get; set; }
    public string CustomerName { get; set; }
}
...
Debug.Assert(item.Customer != null);
Debug.Assert(item.Customer.CustomerName == "n");  
于 2013-04-19T15:18:31.160 に答える
3

私はレポでこれを一般的に行い、ユースケースに適しています。分かち合おうと思いました。誰かがこれをさらに拡張するかもしれません。

いくつかの欠点は次のとおりです。

  • これは、外部キー プロパティが子オブジェクトの名前 + "Id"、たとえば UnitId であると想定しています。
  • 親に1つの子オブジェクトのみをマッピングしています。

コード:

    public IEnumerable<TParent> GetParentChild<TParent, TChild>()
    {
        var sql = string.Format(@"select * from {0} p 
        inner join {1} c on p.{1}Id = c.Id", 
        typeof(TParent).Name, typeof(TChild).Name);

        Debug.WriteLine(sql);

        var data = _con.Query<TParent, TChild, TParent>(
            sql,
            (p, c) =>
            {
                p.GetType().GetProperty(typeof (TChild).Name).SetValue(p, c);
                return p;
            },
            splitOn: typeof(TChild).Name + "Id");

        return data;
    }
于 2016-04-27T21:06:47.840 に答える