Skip to content

Database: Fix/database query activities failing parameters conversion from DBNull (71685)#445

Open
theloginerror wants to merge 2 commits intoUiPath:developfrom
theloginerror:fix/Database_queries_returning_DBNull_parameters
Open

Database: Fix/database query activities failing parameters conversion from DBNull (71685)#445
theloginerror wants to merge 2 commits intoUiPath:developfrom
theloginerror:fix/Database_queries_returning_DBNull_parameters

Conversation

@theloginerror
Copy link
Copy Markdown
Contributor

Fixed ExecuteQuery and ExecuteNonQuery throwing an exception when trying to convert the parameter of type DBNull returned by the query:
A value of type 'System.DBNull' cannot be set to the location with name 'Argument1' because it is a location of type 'System.String'

https://uipath.atlassian.net/browse/STUD-71685

}
else
{
currentParam.Set(asyncCodeActivityContext, null);
Copy link
Copy Markdown
Collaborator

@viogroza viogroza Oct 17, 2024

Choose a reason for hiding this comment

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

I would remove the condition on else
if there is nothing to set, I would not set null; (this is a business requirement)
for example if I have a in/out param with the initial value 100, then the procedures value for the param is DbNull.. do we want to set to zero the value in this case? or let it as it was? we can use default instead of null if needed

also null assignment wouldn't work if the type is a value type (eg. integer or bool);
eg.:
object o = null;
bool v = (bool)o;

@alexandru-petre
Copy link
Copy Markdown
Collaborator

Good fix — passing DBNull.Value directly to Argument.Set() would fail at runtime. Converting to null is the right direction.

One edge case to consider: value types. If an Out/InOut parameter is InArgument<int> and the procedure returns NULL, the current code calls currentParam.Set(context, null) which will throw — value types can't hold null.

The ADO.NET/Dapper/EF Core consensus for DBNull mapping is:

  • Reference types (string) → null
  • Nullable value types (int?) → null
  • Non-nullable value types (int) → default(T) (0 for int, false for bool, etc.)

Suggested approach:

if (param.Value.Value == DBNull.Value)
{
    var argType = currentParam.ArgumentType;
    if (!argType.IsValueType || Nullable.GetUnderlyingType(argType) != null)
    {
        currentParam.Set(asyncCodeActivityContext, null);
    }
    else
    {
        currentParam.Set(asyncCodeActivityContext, Activator.CreateInstance(argType));
    }
}
else
{
    currentParam.Set(asyncCodeActivityContext, param.Value.Value);
}

Same change applies to both ExecuteNonQuery.cs and ExecuteQuery.cs (identical pattern at the same location).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants