Dapper: Missing SplitOn with QuerySingle or QueryFirst

Created on 1 Sep 2016  路  9Comments  路  Source: StackExchange/Dapper

Was support for SplitOn omitted by design from the QuerySingle and QueryFirst functions?
Have I overlooked something or misunderstood their intended purpose?

Most helpful comment

Say I'm querying single Order and want to join in the customer Profile. My Order looks something like:
C# public class Order { public int Id { get; set; } public decimal Total { get; set; } public Customer Customer { get; set; } }
Am I missing something, or is this the use case described for QueryFirst having SplitOn? Right now I'm using Query and then .FirstOrDefault(). I suppose I could use a custom map, but that sounds tedious. I could also use two queries but that seems ridiculous.

All 9 comments

Since their intended purpose is just querying for a single type, there's no need to split for multiple types.

Hi, thanks for the reply. I imagine wanting to return a single instance/type filled with several child properties is a fairly common use-case. (For example: User with User.Team filled) So, I'm not quite sure I understand the reasoning behind limiting their purpose.

I can see where this might get tricky with one-to-many joins and getting unexpected results. If I were trying to return a single Order with Order.Items filled using a JOIN then you would probably end up only with the first Item of the Order. But I'm not sure this scenario should hold back the convenience of a SplitOn for the previous scenario.

In this case, you'd use a Query<T, T2, TResult> call (what we call multi-map), that's the only case in which a splitOn makes sense...where does the split happen before reading the next object? It defaults to Id columns. Since the methods you're talking about _only_ return the one type...there's no split involved at all, and therefore no parameter.

Understood. I'm not arguing to use SplitOn with the functions as they are now. I was assuming that support for SplitOn implied adding support for additional types <T,T2,T3,...>.

That said, the real question is will QuerySingle & QueryFirst have multi-map support added in the future? On the surface they appear to be simple and convenient helpers that are currently limited. I was merely curious as to whether there was a fundamental design issue that I wasn't considering for why additional types <T,T2,T3,...> were omitted.

It feels a bit silly to be able to do this when only T is involved:
var user = conn.QueryFirst<User>("SQL");

But then have to switch to this just because I want to multi-map:
var user = conn.Query<User, Address, User>("SQL", ...).First();

I think the honest answer is "that's just more overloads than we want to maintain". And generally, when loading _only a single row_, that optimization passed to the data provider is less effectual in terms of overall impact percentage. We already have a lot of methods, and async methods, and generic overload counts and...it's just a matter of: is the use case percentage or performance benefit worth maintaining x amount bigger code?

Think about every API change (e.g. oops, we need to add parameter X to all of these), which means _another_ set of them to maintain backwards compatibility. That's just one example, but the maintenance and noise really adds up on these, so unless there's a high demand for such overloads, we're admittedly reluctant to add them.

Say I'm querying single Order and want to join in the customer Profile. My Order looks something like:
C# public class Order { public int Id { get; set; } public decimal Total { get; set; } public Customer Customer { get; set; } }
Am I missing something, or is this the use case described for QueryFirst having SplitOn? Right now I'm using Query and then .FirstOrDefault(). I suppose I could use a custom map, but that sounds tedious. I could also use two queries but that seems ridiculous.

I too would like to know how to handle @r-tanner-f 's situation. Because I'm in that same boat.

Yep, I'm also in need of this scenario. Thanks

Same. This is an extremely common use case.

Was this page helpful?
0 / 5 - 0 ratings