Reputation: 5913
I want to execute a single Query (or Stored Proc with multiple resultsets). I know how to do Multi-mapping using Dapper, but I can't sort how to map the two collections onto the same parent. Basically, given this Object definition...
class ParentObject
{
string Name { get; set; }
ICollection<ChildObjectOne> ChildSetOne {get;set;}
ICollection<ChildObjectTwo> ChildSetTwo { get; set; }
}
class ChildObjectOne
{
string Name { get; set; }
}
class ChildObjectTwo
{
int id { get; set; }
string LocationName { get; set; }
}
I want to be able to run a Dapper query that somehow yields:
IQueryable<ParentObject> result = cnn.Query(
// Some really awesome dapper syntax goes here
);
Upvotes: 6
Views: 7216
Reputation: 662
It is possible to materialize an object with one-to-many relationships using the IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TReturn>(this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TReturn> map);
method in this case. However you need to make a few changes to the entities in order to have enough information to do so.
Here are a few SO threads with similar questions.
How do I map lists of nested objects with Dapper
Extension function to make it cleaner
Dapper.Net by example - Mapping Relationships
public class ParentObject
{
public ParentObject()
{
ChildSetOne = new List<ChildObjectOne>();
ChildSetTwo = new List<ChildObjectTwo>();
}
// 1) Although its possible to do this without this Id property, For sanity it is advisable.
public int Id { get; set; }
public string Name { get; set; }
public ICollection<ChildObjectOne> ChildSetOne {get; private set;}
public ICollection<ChildObjectTwo> ChildSetTwo { get; private set; }
}
public class ChildObjectOne
{
// 2a) Need a ParentId
public int ParentId { get; set; }
public string Name { get; set; }
}
public class ChildObjectTwo
{
// 2b) This ParentId is not required but again for sanity it is advisable to include it.
public int ParentId { get; set; }
public int id { get; set; }
public string LocationName { get; set; }
}
public class Repository
{
public IEnumerable<ParentObject> Get()
{
string sql =
@"SELECT
p.Id,
p.Name,
o.Name,
o.ParentId,
t.Id,
t.LocationName,
t.ParentId
FROM
Parent p
LEFT JOIN ChildOne o on o.ParentId = p.Id
LEFT JOIN ChildTwo t on t.ParentId = p.Id
WHERE
p.Name LIKE '%Something%'";
var lookup = new Dictionary<int, ParentObject>();
using (var connection = CreateConnection())
{
connection.Query<ParentObject, ChildObjectOne, ChildObjectTwo, ParentObject>(
sql, (parent, childOne, childTwo) =>
{
ParentObject activeParent;
if (!lookup.TryGetValue(childOne.ParentId, out activeParent))
{
activeParent = parent;
lookup.add(activeParent.Id, activeParent);
}
//TODO: if you need to check for duplicates or null do so here
activeParent.ChildSetOne.Add(childOne);
//TODO: if you need to check for duplicates or null do so here
activeParent.ChildSetTwo.Add(childTwo);
});
}
return lookup.Values;
}
}
Upvotes: 3
Reputation: 8116
Not sure if you DON'T want to use MultiMapping but here's how it would work for your case. As far as I know and read on SO, is not not possible to map a deep nested object graph with a simple Query
.
static void Main(string[] args)
{
var sqlParent = "SELECT parentId as Id FROM ParentTable WHERE parentId=1;";
var sqlChildOneSet = "SELECT Name FROM ChildOneTable;"; // Add an appropriate WHERE
var sqlChildTwoSet = "SELECT Id, LocationName FROM ChildTwoTable;"; // Add an appropriate WHERE
var conn = GetConnection() // whatever you're getting connections with
using (conn)
{
conn.Open();
using (var multi = conn.QueryMultiple(sqlParent + sqlChildOneSet + sqlChildTwoSet))
{
var parent = multi.Read<ParentObject>().First();
parent.ChildSetOne = multi.Read<ChildOne>().ToList();
parent.ChildSetTwo = multi.Read<ChildTwo>().ToList();
}
}
}
Similar questions for nested objects and dapper :
https://stackoverflow.com/search?q=nested+objects+%2B+dapper
Upvotes: 8