領域對象:Game(游戲), Room(游戲群),兩者一對多的關係,SQL語句中會用到JOIN 通常用Dapper的Query<TFirst,TSecond,TReturn>() 或 QueryAsync<TFirst,TSecond,TReturn>() 是可以實現,但是去除重覆記錄比較麻煩。 所 ...
領域對象:Game(游戲), Room(游戲群),兩者一對多的關係,SQL語句中會用到JOIN
public class Game : AggregateRoot { public string Tag { get; set; } public string Title { get; set; } public string Description { get; set; } public IEnumerable<Room> Rooms { get; set; } public Game() { this.Rooms = new HashSet<Room>(); } public void SetRooms(IEnumerable<Room> rooms) { this.Rooms = this.Rooms.Concat(rooms); } } public class Room : Entity { public int GameId{ get; set; } public intstring Name { get; set; } public int Limit { get; set; } public string Owner { get; set; } }
通常用Dapper的Query<TFirst,TSecond,TReturn>() 或 QueryAsync<TFirst,TSecond,TReturn>() 是可以實現,但是去除重覆記錄比較麻煩。
所以我們擴展兩個Query/QueryAsync方法:
/// <summary> /// 查詢帶聚合導航屬性的對象集合 /// </summary> /// <typeparam name="TFirst">主體對象類型</typeparam> /// <typeparam name="TSecond">聚合導航對象類型</typeparam> /// <param name="setting">設置聚合導航屬性的方法</param> public static IEnumerable<TFirst> Query<TFirst, TSecond>(this IDbConnection cnn, string sql, Action<TFirst, TSecond> setting, object param = null, string splitOn = "Id") where TFirst : class, IEntity<int> where TSecond : class, IEntity<int> { TFirst lookup = null; var hashes = new HashSet<TFirst>(); cnn.Query<TFirst, TSecond, TFirst>(sql, (first, second) => { //第一條記錄,或者新的主體記錄,否則lookup還是上一條記錄 if (lookup == null || lookup.Id != first.Id) lookup = first; if (second != null && second.Id > 0 && setting != null) setting(lookup, second); if (!hashes.Any(m => m.Id == lookup.Id)) hashes.Add(lookup); return null; }, param: param, splitOn: splitOn); return hashes; } /// <summary> /// 非同步查詢帶聚合導航屬性的對象集合 /// </summary> /// <typeparam name="TFirst">主體對象類型</typeparam> /// <typeparam name="TSecond">聚合導航對象類型</typeparam> /// <param name="setting">設置聚合導航屬性的方法</param> public static async Task<IEnumerable<TFirst>> QueryAsync<TFirst, TSecond>(this IDbConnection cnn, string sql, Action<TFirst, TSecond> setting, object param = null, string splitOn = "Id") where TFirst : class, IEntity<int> where TSecond : class, IEntity<int> { TFirst lookup = null; var hashes = new HashSet<TFirst>(); await cnn.QueryAsync<TFirst, TSecond, TFirst>(sql, (first, second) => { //第一條記錄,或者新的主體記錄,否則lookup還是上一條記錄 if (lookup == null || lookup.Id != first.Id) lookup = first; if (second != null && second.Id > 0 && setting != null) setting(lookup, second); if (!hashes.Any(m => m.Id == lookup.Id)) hashes.Add(lookup); return null; }, param: param, splitOn: splitOn); return hashes; }
調用示例:
return await _db.QueryAsync<Game, Room>("SELECT * FROM game g LEFT JOIN room r ON r.gameid = g.id", (game, room) => { game.SetRooms(new HashSet<Room> { room }); }, splitOn: "Id");