Dapper icon indicating copy to clipboard operation
Dapper copied to clipboard

Missing implicit numeric cast of decimal to integer in C# record

Open DottorPagliaccius opened this issue 2 years ago • 4 comments

Hi, I've found that Dapper behaves differently when using plain classes or records (working on Oracle 12).

When getting results from a command, like

return await connection.QueryAsync<SomeObject>(query);

this

public class SomeObject
{
    public int Id { get; set; }
}

works fine while this

public record SomeObject(int Id)

throws

System.InvalidOperationException: A parameterless default constructor or one matching signature (System.Decimal ID) is required for SomeNamespace.SomeObjectmaterialization

If I change property data type, like this

public record SomeObject(decimal Id)

it works, but I don't want to use decimal instead of int.

DottorPagliaccius avatar Jul 07 '23 16:07 DottorPagliaccius

Anyone? :/

DottorPagliaccius avatar Sep 01 '23 14:09 DottorPagliaccius

Well, the good news is that in DapperAOT this should work identically in the two modesb- but DapperAOT is dependent on new compiler features in the net8 release (note: it is not dependent on net8 itself - just the build tools / build SDK). The constructor path in vanilla Dapper is ... limited. I'll take a look later to see what the current state is.

mgravell avatar Sep 02 '23 07:09 mgravell

Your Oracle number is probably unconstrained, e.g. NUMBER instead of NUMBER(9,0). This seems to always map to System.Decimal even if the query rounds or casts the number.

For example, this errors unless the destination object has System.Decimal for some_column: SELECT CAST (round(some_unconstrained_number, 3) AS NUMBER(18,15)) some_column FROM dual

I have never found a workaround for this other than modifying the structure of the table.

burnchar avatar Dec 06 '23 18:12 burnchar

Correction, I do have some code that uses Oracle's TO_BINARY_DOUBLE() function in the SQL, which does map to a System.Double. This is not great as the SQL needs to be modified, but works when you cannot change the database structure, which is often. It would be preferable for the mapper to map any number type to System.Double and throw an exception if the contents do not fit, but I understand this is not possible from an earlier discussion.

burnchar avatar Dec 06 '23 18:12 burnchar