领域对象: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 > && 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 > && 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");
05-11 10:54