2012-10-19 128 views
19

我有一個存儲過程返回多個結果集。我正在用精巧的方式執行此操作。Dapper Multi QueryMultiple映射

其中一個結果集是Person JOIN Checks,其中Person可以有多個Checks。

最終目標是讓不同的人員對象具有檢查對象的集合。

QueryMutliple給我一個Sqlmapper.GridReader。我看到SqlMapper.GridReader.Read()的過載需要Func<TFirst, TSecond, TReturn>

有沒有例子說明如何使用它?

回答

5

這裏就是我得到了它的工作:

var q = _sqlConnection.QueryMultiple("MySproc", 
            myParams, 
            commandType: CommandType.StoredProcedure); 
var set1 = q.Read<Set1Type>(); 

var set2Func = new Func<Person, Check, Person>((p, c) => { 
    p.CheckAlert = c; 
    return p; 
}); 

var set2 = q.Read(set2Func, "CheckId") 
      .GroupBy(x => x.PersonId) 
      .Select(x => { 
       var person = x.First(); 
       person.Checks = x.Select(p => p.Check).ToArray(); 
       person.Check = null; // i really don't like this 
       return person; 
      }) 
      .ToArray(); 

正如評論說,我不喜歡的人對象上的不必要的檢查屬性。

我仍然喜歡聽到更好的方法來做到這一點。

+2

+1,但它可能是值得*不*接受這個作爲答案,如果你正在尋找一個更好的方式來做到這一點,因爲沒有回答的問題似乎吸引了更多的關注。 – dumbledad

+0

什麼是「CheckId」,你從哪裏得到? – dumbledad

+0

明白了 - 這是[splitOn:](http://stackoverflow.com/a/7478958/575530)參數 – dumbledad

4

這是我使用的解決方案的一個版本。我使用繼承層次而不是將屬性設置爲null來解決Ronnie在his answer中提出的問題,但它相當於同樣的事情。

以下是SQL:用戶有項目和集合,項目可以在集合中。

CREATE TABLE Users 
(id UNIQUEIDENTIFIER DEFAULT (NEWID()) NOT NULL, 
name NVARCHAR (MAX) NULL, 
email NVARCHAR (128) NULL, 
PRIMARY KEY (id)) 

CREATE TABLE Items 
(id UNIQUEIDENTIFIER DEFAULT (NEWID()) NOT NULL, 
userId UNIQUEIDENTIFIER NOT NULL, 
name NVARCHAR (MAX) NULL, 
description NVARCHAR (MAX) NULL, 
PRIMARY KEY (id), 
FOREIGN KEY (userId) REFERENCES Users (id)) 

CREATE TABLE Collections 
(id UNIQUEIDENTIFIER DEFAULT (NEWID()) NOT NULL, 
userId UNIQUEIDENTIFIER NOT NULL, 
name NVARCHAR (MAX) NULL, 
layoutSettings NVARCHAR (MAX) NULL, 
PRIMARY KEY (id), 
FOREIGN KEY (userId) REFERENCES Users (id)) 

CREATE TABLE CollectedItems 
(itemId UNIQUEIDENTIFIER NOT NULL, 
collectionId UNIQUEIDENTIFIER NOT NULL, 
PRIMARY KEY CLUSTERED (itemId, collectionId), 
FOREIGN KEY (itemId) REFERENCES Items (id), 
FOREIGN KEY (collectionId) REFERENCES Collections (id)) 

現在是數據模型類。爲了處理多重查詢的Dapper多重映射,集合比我期望的要複雜一些。

public class User 
{ 
    public Guid Id { get; set; } 
    public string Name { get; set; } 
    public string Email { get; set; } 
    public List<Item> Items { get; set; } 
    public List<Collection> Collections { get; set; } 
} 

public class Item 
{ 
    public Guid Id { get; set; } 
    public Guid UserId { get; set; } 
    public string Name { get; set; } 
    public string Description { get; set; } 
} 

public class CoreCollection 
{ 
    public Guid Id { get; set; } 
    public Guid UserId { get; set; } 
    public string Name { get; set; } 
    public string LayoutSettings { get; set; } 
} 

public class PartialDataCollection : CoreCollection 
{ 
    public Guid ItemId { get; set; } 
} 

public class Collection : CoreCollection 
{ 
    public List<Guid> ItemIds { get; set; } 
} 

public class CollectedItem 
{ 
    public Guid ItemId { get; set; } 
    public Guid CollectionId { get; set; } 
    public DateTime CreatedAt { get; set; } 
} 

最後我們有一個使用小巧玲瓏的多映射與多個查詢

控制器方法
[Route("GetUser/{id}")] 
public User GetUser(Guid id) 
{ 
    var sql = @"SELECT * FROM Users WHERE id = @id 
       SELECT * FROM Items WHERE userId = @id 
       SELECT * FROM Collections 
        LEFT OUTER JOIN CollectedItems ON Collections.id = CollectedItems.collectionId 
        WHERE userId = @id"; 
    using (var connection = new SqlConnection(ConnectionString)) 
    { 
     var multi = connection.QueryMultiple(sql, new { id = id }); 
     var user = multi.Read<User>().Single(); 
     var items = multi.Read<Item>().ToList(); 
     var partialDataCollections = multi.Read<PartialDataCollection, CollectedItem, PartialDataCollection>(AddCollectedItem, splitOn: "itemId").ToList(); 

     user.Items = items; 

     user.Collections = partialDataCollections.GroupBy(
      pdc => pdc.Id, 
      (key, group) => new Collection 
      { 
       Id = key, 
       UserId = group.First().UserId, 
       Name = group.First().Name, 
       LayoutSettings = group.First().LayoutSettings, 
       ItemIds = group.Select(groupMember => groupMember.ItemId).ToList() 
      }).ToList(); 

     return user; 
    } 
} 

private PartialDataCollection AddCollectedItem(PartialDataCollection collection, CollectedItem collectedItem) 
{ 
    if (collection != null && collectedItem != null) 
    { 
     collection.ItemId = collectedItem.ItemId; 
    } 
    return collection; 
} 

如果羅尼是擔心在his answer設置person.Check = null我擔心我的回答額外的複雜性,從加入類PartialDataCollection到我的模型。但我看不到一個簡單的方法。

(注:我已經在GitHub上衣冠楚楚項目提出這個作爲an issue。)