DapperLib / DapperLib/Dapper

Querying abstract types

Open
#262 22 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

[Table("Animal")]
public abstract class Animal
{
    public int AnimalId { get; set; }
    public string Discriminator { get { return GetType().Name; } }
}

[Table("Animal")]
public class Bird : Animal
{
    public string FeatherColour { get; set; }
}

[Table("Animal")]
public class Dog : Animal
{
    public string FurColour { get; set; }
}
var animals = Connection.Query<Animal>("SELECT * FROM Animal")

When doing the query above you get the exception Instances of abstract classes cannot be created. I would hope that this would return a list of animals with their values being their respective derived types.

In my case I'm using TPH inheritance so there's a field on the Animal table that specifies the derived type.

My attempts to add support for this have been unsuccessful. Before SqlMapper.cs::GetTypeDeserializer() is called if the type being passed in is an abstract class then I replace the type with the one returned in the following method:

static Type GetDerivedType(Type abstractType, IDataReader reader)
{
    var discriminator = abstractType.GetProperty("Discriminator");
    if (discriminator == null)
        throw new InvalidOperationException("Cannot create instance of abstract class " + abstractType.FullName + ". To allow dapper to map to a derived type, add a Discriminator field that stores the name of the derived type");

    return Type.GetType((string)reader["Discriminator"]);
}

However it looks like at this point the reader hasn't been opened so it fails with Invalid attempt to read when no data is present.

Any recommendations on how to proceed? If there has been an effort to implement this elsewhere, please let me know!

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 in SqlMapper.cs::GetTypeDeserializer() and review how the reader is accessed during Query. Compare that flow with the reported GetDerivedType attempt and the TPH Discriminator field. Done means querying the abstract Animal type can return instances of the appropriate derived types without the abstract-class exception.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, sql
Domain
backend, database
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.