DapperLib / DapperLib/Dapper

Odd behaviour with Execute(Async) and typed IEnumerable<T>

Open
#1,708 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C#
Stars
18.4k
Forks
3.7k
Avg merge
5h 8m
Merged PRs (30d)
1

Description

There seems to be a rather odd behaviour when passing a typed enumerable or collection to ExecuteAsync (and probably the sync version as well).

If the first item in a typed collection is a derived type, it appears Dapper will attempt to cast all other items in the collection to whatever type the first item is, even if that type is not compatible with the base type used for the collection.

Example:

public class TestDao
{
  public string Name { get; set; }
  public int Age { get; set; }
}

// This class corresponds to a view in the database
public class DerivedTestDao : TestDao
{
  public string Magic { get; set; }
}

// ... later in a method working against the DB:
IEnumerable<TestDao> daos = new[] {
  new DerivedTestDao { ... },
  new TestDao { ... }
};

var query = "<some SQL to perform an insert/update/merge in the `Test` table>";
var result = await dbConnection.ExecuteAsync(query, daos);

Somewhere down the chain from ExecuteAsync, Dapper reaches a method that takes an IEnumerable (non-generic), and so the type information of the enumerable is lost (SqlMapper.ExecuteMultiImplAsync).
From what I can gather, Dapper assumes every object in the IEnumerable is (or derives from) the type of the first object in the IEnumerable, and will then attempt to cast all remaining objects to this first type. This of course breaks in the above scenario.

Have I missed something to be able to pass derived types in this manner, or is there a different method I should be using?

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at ExecuteAsync and SqlMapper.ExecuteMultiImplAsync, using the mixed DerivedTestDao/TestDao IEnumerable example from the issue to reproduce the cast failure. Trace where the first item's type is selected and verify behavior for both asynchronous and synchronous execution. Done means compatible derived and base instances can be processed without an invalid cast.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, sql
Domain
backend, database
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.