Returning model in a custom Poco object using Dapper

Viewed 714

I am aggregating the data using following query:

var result = Connection.Query<TransactionStatsByUserGrouped>(
    @"SELECT usr.*, st.Amount, st.Count
    FROM Users usr
    RIGHT JOIN (select UserId, sum(Amount) as Amount, sum(Count) Count
        FROM (
            SELECT User2Id as UserId, sum(Amount) as Amount, count(TransactionId) Count
            FROM Transactions
            WHERE User1Id = @UserId
            GROUP BY User2Id
    ) t GROUP BY UserId) st
    ON st.UserId = usr.UserId
    ORDER BY st.Amount DESC",
    param: new { UserId = userId },
    transaction: Transaction
);

The custom Poco object has following structure:

public class TransactionStatsByUserGrouped
{
    public User User { get; set; }
    public decimal Amount { get; set; }
    public int Count { get; set; }
}

Where User is an actual data model, containing following properties:

public class User
{
    public string UserId { get; set; }
    public string Email { get; set; }
    public int Role { get; set; }
    public string Password { get; set; }
    // ...
}

The problem I am having is that I get null result for the User model in TransactionStatsByUserGrouped class:

[
    {
        "user": null,
        "amount": 400.00,
        "count": 2
    },
    {
        "user": null,
        "amount": 100.00,
        "count": 1
    }
]

The issue seems to be with the fact, that custom TransactionStatsByUserGrouped class is using the model as a property, rather than all model's properties listed as a separate property in a TransactionStatsByUserGrouped class. Is there a work around for this? I don't want to map each and single User model property manually.

I would like to return all properties of a user + aggregated stats for each - all in a single query.

.Net Core 2 is used + Dapper + MySQL connector (MariaDB)

1 Answers

According to documentation you can try Multi Mapping

var sql = 
  @"SELECT usr.*, st.Amount, st.Count
    FROM Users usr
    RIGHT JOIN (select UserId, sum(Amount) as Amount, sum(Count) Count
        FROM (
            SELECT User2Id as UserId, sum(Amount) as Amount, count(TransactionId) Count
            FROM Transactions
            WHERE User1Id = @UserId
            GROUP BY User2Id
    ) t GROUP BY UserId) st
    ON st.UserId = usr.UserId
    ORDER BY st.Amount DESC";

var result = Connection.Query<TransactionStatsByUserGrouped, User, TransactionStatsByUserGrouped>(
    sql,
    (group, user) => { group.User = user; return group;},
    param: new { UserId = userId },
    transaction: Transaction
);
Related