Dapper實現一對多對象關系聚合導航屬性


領域對象: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");

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM