Search code examples
c#.netdapper

Can I throw an exception when mapping a DBNull with Dapper?


Let's assume that I have a class model that I would like to have non-default values in

public class MyModel()
{
    public int PropertyOne { get; set; }
    public int? PropertyTwo { get; set; }
    public string PropertyThree { get; set; }
}

And let's say that I query for MyModel with this query

SELECT
   NULL as PropertyOne,
   NULL as PropertyTwo,
   NULL as PropertyThree

If I map this to MyModel class, I will have PropertyOne = 0, PropertyTwo = null, PropertyThree = null.

By default Dapper will not call any setters if it encounters a DBNull value when reading, so PropertyOne has a default value of an int which is 0.

  1. I don't want that, I would like to verify that I would always get a non-null value for PropertyOne from my query and I'd like to get an exception if the reader encounters a DBNull.

  2. Let's say that I also don't want to have a null value for PropertyThree. Can I also achieve this check somehow with Dapper when mapping happens? And can I do this by using an attribute like in the model below?

public class MyModel()
{
    public int PropertyOne { get; set; }
    public int? PropertyTwo { get; set; }
    [NotDBNull]
    public string PropertyThree { get; set; }
}

So ideally what I want to achieve is use the above model and have the following logic:

Case 1: PropertyOne gets DBNull, but it's not nullable => throw an exception

Case 2: PropertyTwo gets DBNull, but it's nullable => all good

Case 3: PropertyThree gets DBNull, but is marked with [NotDBNull] attribute => throw an exception

Is there any way that I can achieve this with Dapper without using other forms of validation?


Solution

  • Dapper.AOT works (I hope! It is meant to) in the way you describe, for both value-types and reference-types (the latter if NRTs are enabled in the source).

    It isn't possible for me to know from your code whether NRTs are enabled, but:

    • string with NRTs enabled means "actively expect non-null"
    • string? with NRTs enabled means "allow null"
    • string without NRTs enabled means "allow null"
    • int means "actively expect non-null"
    • int? means "allow null"

    So: try Dapper.AOT and see how it goes! Depending on feedback we may add an attribute to soften this behaviour back to Dapper vanilla's null handling, but: what you describe is how we want things to work going forward.