领域对象: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");