mirror of
https://github.com/DapperLib/Dapper.git
synced 2026-10-18 14:27:47 +08:00
129 lines
5.5 KiB
C#
129 lines
5.5 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Xunit;
|
|
using Child = Dapper.Tests.MultiMapTests.Child;
|
|
using Parent = Dapper.Tests.MultiMapTests.Parent;
|
|
|
|
namespace Dapper.Tests
|
|
{
|
|
public class MultiMapTupleTests : TestBase
|
|
{
|
|
// note: implementation is not optimized yet - just basic reflection, no IL crazy
|
|
// intent: to explore the API, allowing horizontally partitioned data to be fetched
|
|
// more convenienty by expressing them as tuples; this is similar to the (hard to use)
|
|
// pre-existing multi-generic Query<...> API that does the same, i.e.
|
|
// similar to connection.Query<Parent,Child,Parent>(...) - which folks find hard to grok
|
|
|
|
// here are 3 possible ideas for expressing that
|
|
[Fact]
|
|
public void GetRawTuples_Manual() // here we use an explicit map function that returns the entire row, and
|
|
// in doing so provides the contextual name metadata
|
|
{
|
|
var tuples = connection.Query(
|
|
@"select 1 as [Id], 1 as [Id] union all select 1,2 union all select 2,3 union all select 1,4 union all select 3,5",
|
|
((Parent parent, Child child)row) => row
|
|
).AsList();
|
|
|
|
tuples.Count.IsEqualTo(5);
|
|
|
|
string.Join(",", tuples.Select(x => $"({x.parent.Id},{x.child.Id})")).IsEqualTo(
|
|
"(1,1),(1,2),(2,3),(1,4),(3,5)");
|
|
}
|
|
|
|
[Fact]
|
|
public void GetRawTuples_Passthru() // here we use a declarative map function, so all we provide is the T to Map<T>
|
|
{
|
|
var tuples = connection.Query(
|
|
@"select 1 as [Id], 1 as [Id] union all select 1,2 union all select 2,3 union all select 1,4 union all select 3,5",
|
|
SqlMapper.Map<(Parent parent, Child child)>()
|
|
).AsList();
|
|
|
|
tuples.Count.IsEqualTo(5);
|
|
|
|
string.Join(",", tuples.Select(x => $"({x.parent.Id},{x.child.Id})")).IsEqualTo(
|
|
"(1,1),(1,2),(2,3),(1,4),(3,5)");
|
|
}
|
|
|
|
[Fact]
|
|
public void GetRawTuples_Split() // here we provide the tuple metadata via the T in QuerySplit<T> - note the name
|
|
// is different to avoid ambiguity with the primary Query<T> which does something else
|
|
{
|
|
var tuples = connection.QuerySplit<(Parent parent, Child child)>(
|
|
@"select 1 as [Id], 1 as [Id] union all select 1,2 union all select 2,3 union all select 1,4 union all select 3,5"
|
|
).AsList();
|
|
|
|
tuples.Count.IsEqualTo(5);
|
|
|
|
string.Join(",", tuples.Select(x => $"({x.parent.Id},{x.child.Id})")).IsEqualTo(
|
|
"(1,1),(1,2),(2,3),(1,4),(3,5)");
|
|
}
|
|
|
|
// these are more complex examples that make use of a non-trivial mapping function to play with the horizontal partitions *before*
|
|
// yielding them - for example, to take parent/child data and stitch it together such that the children are attached to the parents
|
|
|
|
// compare and contrast: MultiMapTests.ParentChildIdentityAssociations
|
|
[Fact]
|
|
public void ParentChildIdentityAssociations()
|
|
{
|
|
var lookup = new Dictionary<int, Parent>();
|
|
var parents = connection.Query(@"select 1 as [Id], 1 as [Id] union all select 1,2 union all select 2,3 union all select 1,4 union all select 3,5",
|
|
((Parent parent, Child child) row) =>
|
|
{
|
|
if (!lookup.TryGetValue(row.parent.Id, out Parent found))
|
|
{
|
|
lookup.Add(row.parent.Id, found = row.parent);
|
|
}
|
|
found.Children.Add(row.child);
|
|
return found;
|
|
}).Distinct().ToDictionary(p => p.Id);
|
|
parents.Count.IsEqualTo(3);
|
|
parents[1].Children.Select(c => c.Id).SequenceEqual(new[] { 1, 2, 4 }).IsTrue();
|
|
parents[2].Children.Select(c => c.Id).SequenceEqual(new[] { 3 }).IsTrue();
|
|
parents[3].Children.Select(c => c.Id).SequenceEqual(new[] { 5 }).IsTrue();
|
|
}
|
|
|
|
// compare and contrast: MultiMapTests.TestMultiMap
|
|
[Fact]
|
|
public void TestMultiMap()
|
|
{
|
|
const string createSql = @"
|
|
create table #Users (Id int, Name varchar(20))
|
|
create table #Posts (Id int, OwnerId int, Content varchar(20))
|
|
|
|
insert #Users values(99, 'Sam')
|
|
insert #Users values(2, 'I am')
|
|
|
|
insert #Posts values(1, 99, 'Sams Post1')
|
|
insert #Posts values(2, 99, 'Sams Post2')
|
|
insert #Posts values(3, null, 'no ones post')
|
|
";
|
|
connection.Execute(createSql);
|
|
try
|
|
{
|
|
const string sql =
|
|
@"select * from #Posts p
|
|
left join #Users u on u.Id = p.OwnerId
|
|
Order by p.Id";
|
|
|
|
var data = connection.Query(sql, ((Post post, User user) row) => { row.post.Owner = row.user; return row.post; }).ToList();
|
|
var p = data.First();
|
|
|
|
p.Content.IsEqualTo("Sams Post1");
|
|
p.Id.IsEqualTo(1);
|
|
p.Owner.Name.IsEqualTo("Sam");
|
|
p.Owner.Id.IsEqualTo(99);
|
|
|
|
data[2].Owner.IsNull();
|
|
}
|
|
finally
|
|
{
|
|
connection.Execute("drop table #Users drop table #Posts");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
}
|