Skip to content

Introducing parameters' DbType before passing on to the database - MsSql - #1442

Merged
ayush3797 merged 28 commits into
mainfrom
dev/agarwalayush/parameterTypeForParamsToDb
May 3, 2023
Merged

Introducing parameters' DbType before passing on to the database - MsSql#1442
ayush3797 merged 28 commits into
mainfrom
dev/agarwalayush/parameterTypeForParamsToDb

Conversation

@ayush3797

@ayush3797 ayush3797 commented Apr 18, 2023

Copy link
Copy Markdown
Contributor

Why make this change?

Fixes #475
Most column types will accept a string null and the db will automatically infer our intention, but for varbinary in MsSql the db complains that it cannot convert varchar to varbinary. For more details about the issue refer: https://stackoverflow.com/questions/29254690/why-does-dbnull-value-require-a-proper-sqldbtype

What is this change?

Changing how we form the parameters as we pass them to the database. Previously we used to only pass the parameter's value. Now, we would also pass the parameter's DbType along with the value as suggested in the stack overflow article.

Notes:

  1. We would only be passing the DbType for MsSql.
  2. Usually, we haven't seen any need to pass the DbType for Sql Server data types other than varbinary. However, we will still be supplying the DbType for all other parameter's for which we are confirmed about the 1:1 mapping from SystemType to DbType. Sql server datatypes like datetime, datetime2 are all treated as datetime by dotnet, so there is no 1:1 mapping for datetime datatypes. So we are skipping supplying the DbType for these.
  3. As explained in this stack overflow article here, the GUID when converted to string, is output in lowercase. That's why when the query to verify the MsSql test InsertOneInSupportedTypes is written, we have explicitly cast guid_types to lower case.

Additional change

  1. The real sql server datatype was incorrectly mapped to long dotnet type. It has been correctly mapped to decimal now.

Issue with DateTime/DateTimeOffset Sql Server data types

For a mutation request like this, we get a response:
image

and the parameters are generated as:
image

the parameter generated is of type DateTimeOffset (as evident from the value highlighted) but the underlying Sql Server datatype for the datetime_types field is datetime. Even though we supplied a value 1999-01-08 09:20:00 in the mutation, it became 08-01-1999 09:20:00 +05:30, because that's how graphql treats datetime/datetimoffset/date types. Then this implicit conversion from a value of type DateTimeOffset to DateTime cannot happen throwing an exception with message : Failed to convert parameter value from a DateTimeOffset to a DateTime. Hence we cannot add a mapping from typeof(DateTime) = DbType.DateTime.

Another option that came to my mind and would probably come to your mind as well would be to have a mapping fromtypeof(DateTime) = DbType.DateTimeOffset, since then there can be implicit conversion from value of DateTimeOffset type to DbType.DateTimeOffset. But that has its own flaws. Lets look at the below screenshots:

Consider this mutation:
image

and the parameters generated for the query (mutation ran successfully because the default value for the instant PK column was inserted into the table):

image

The parameter value is of sql server type datetime but the DbType is populated as `DbType.DateTimeOffset`. This upcasting cannot happen correctly and so we are returned with 0 records. So, this approach won't work as well.

Conclusion: We won't populate DbType for these sql server types as it is not required and would prevent data loss and any unforeseen exceptions.

How was this tested?

  • Integration Tests
  • Unit Tests - The unit tests that were skipped before saying that bytearray datatype is not supported are now running successfully for MsSql.

Sample Request(s)

Request method: POST
Request URL: https://localhost:5001/api/SupportedType/
Request:

{
    "bytearray_types": null
}

Response:

{
    "value": [
        {
            "typeid": 5001,
            "byte_types": null,
            "short_types": null,
            "int_types": null,
            "long_types": null,
            "string_types": null,
            "single_types": null,
            "float_types": null,
            "decimal_types": null,
            "boolean_types": null,
            "date_types": null,
            "datetime_types": null,
            "datetime2_types": null,
            "datetimeoffset_types": null,
            "smalldatetime_types": null,
            "bytearray_types": null,
            "guid_types": "27742da6-99f2-4e58-9fd8-4f143aea46b0"
        }
    ]
}

@ayush3797 ayush3797 changed the title Dev/agarwalayush/parameter type for params to db Introducing parameters' DbType before passing on to the database - MsSql Apr 18, 2023
@ayush3797 ayush3797 self-assigned this Apr 18, 2023
@ayush3797 ayush3797 added this to the Apr2023 milestone Apr 18, 2023
@ayush3797 ayush3797 added bug Something isn't working enhancement New feature or request mssql an issue thats specific to mssql labels Apr 18, 2023
@ayush3797 ayush3797 linked an issue Apr 18, 2023 that may be closed by this pull request
@ayush3797
ayush3797 marked this pull request as ready for review April 26, 2023 07:54
Comment thread src/Service/Models/DbConnectionParam.cs
Comment thread src/Service/Parsers/ODataASTVisitor.cs Outdated
Comment thread src/Service/Parsers/ODataASTVisitor.cs Outdated
Comment thread src/Service/Resolvers/MsSqlQueryExecutor.cs Outdated
Comment thread src/Service/Resolvers/QueryExecutor.cs
Comment thread src/Service/Services/DbTypeHelper.cs Outdated

@Aniruddh25 Aniruddh25 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this refactoring, discovering new issues and making sure the datatype is correct, no data loss for datetime/offset.
LGTM, after providing explanation in Code why DbType is nullable.

Comment thread src/Config/DatabaseObject.cs
Comment thread src/Service/Models/GraphQLFilterParsers.cs
Comment thread src/Service/Parsers/ODataASTVisitor.cs
Comment thread src/Service/Parsers/ODataASTVisitor.cs
Comment thread src/Service/Resolvers/QueryExecutor.cs
Comment thread src/Service.Tests/SqlTests/RestApiTests/Insert/InsertApiTestBase.cs Outdated
Comment thread src/Service.Tests/Unittests/ODataASTVisitorUnitTests.cs Outdated
@ayush3797
ayush3797 requested a review from seantleonard May 1, 2023 18:44
@ayush3797
ayush3797 enabled auto-merge (squash) May 3, 2023 20:17
Comment thread src/Service/Resolvers/IQueryExecutor.cs
@ayush3797
ayush3797 merged commit 8ab6c18 into main May 3, 2023
@ayush3797
ayush3797 deleted the dev/agarwalayush/parameterTypeForParamsToDb branch May 3, 2023 21:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request mssql an issue thats specific to mssql

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Sql: Specify parameter type when passing parameters to the sql conn

3 participants