Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix null parameter being mistaken for the string type #690

Merged
merged 3 commits into from
Jan 2, 2021

Conversation

fredliex
Copy link
Contributor

Always try to set the DbType of the pameter to avoid the null value being mistaken for the string type.

code

var data = connection.ExecuteQuery<decimal?>("select @value", new { value = (decimal?)null }).First();

exception

System.InvalidOperationException
  HResult=0x80131509
  Message=No coercion operator is defined between types 'System.String' and 'System.Nullable`1[System.Decimal]'.
  Source=System.Linq.Expressions
  StackTrace: 
   at System.Linq.Expressions.Expression.GetUserDefinedCoercionOrThrow(ExpressionType coercionType, Expression expression, Type convertToType)
   at System.Linq.Expressions.Expression.Convert(Expression expression, Type type, MethodInfo method)
   at System.Linq.Expressions.Expression.Convert(Expression expression, Type type)
   at RepoDb.Reflection.Compiler.ConvertExpressionToTypeExpression(Expression expression, Type toType) in D:\Code-git\RepoDB\RepoDb.Core\RepoDb\Reflection\Compiler\Compiler.cs:line 574

analysis

Expression generated by Compiler.GetPlainTypeToDbParametersCompiledFunction is

DbCommand.CreateParameter("name", value, new Nullable<DbType>());

When the third parameter is not specified and the value is null, sql server will treat the parameter as a string.
So DbDataReader.GetFieldType(n) will return DbType.String, the read Expression will use DbDataReader.GetString(n), and then the string will be converted to the return type decimal and an error will occur.

So this PR is mainly to set Parameter.DbType as much as possible to avoid misjudgment of the type when it is null.

If you have any questions, please let me know, and I will modify it as soon as possible.

thank

@mikependon
Copy link
Owner

Thanks for this PR, we will review and revert to you soon. Btw, we just pushed the newly build and might be the last build of this year. So please let us know if this needs to be on beta release so we can issue it for you ASAP.

@fredliex
Copy link
Contributor Author

No time pressure, no need for beta.

thank

// DbType fallback
if (dbType == null)
{
dbType = TypeMapper.GetFallback(classProperty.PropertyInfo.PropertyType);
Copy link
Owner

Choose a reason for hiding this comment

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

We do not need this additional mapping anymore as the code at the line 261 should do this already. If there are issues to this, we should fix it there somehow, not introducing this new mapping.

var dbType = (returnType != null ? clientTypeToDbTypeResolver.Resolve(returnType) : null) ??
                    classProperty.GetDbType() ??
                    value?.GetType()?.GetDbType();

// DbType fallback
if (dbType == null)
{
dbType = TypeMapper.GetFallback(classProperty.PropertyInfo.PropertyType);
Copy link
Owner

@mikependon mikependon Jan 1, 2021

Choose a reason for hiding this comment

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

Same here, the line 520 should do it already.

// DbType fallback
if (dbType == null)
{
dbType = TypeMapper.GetFallback(classProperty.PropertyInfo.PropertyType);
Copy link
Owner

Choose a reason for hiding this comment

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

Same here, the line 333 should do it already.

@fredliex
Copy link
Contributor Author

fredliex commented Jan 2, 2021

The processing method has been changed.
Use ClientTypeToDbTypeResolver instead of TypeMapper.fallback.
And Remove unnecessary logic.

Please review again.
thanks

@@ -334,6 +340,12 @@ private static void EnsureTableValueParameter(IDbDataParameter parameter)
classProperty?.GetDbType() ??
value?.GetType()?.GetDbType();
Copy link
Owner

Choose a reason for hiding this comment

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

The logic is correct now, so I will accept this. Though, you can also remove the additional checking and make it single line like below.

// DbType
var dbType = (returnType != null ? clientTypeToDbTypeResolver.Resolve(returnType) : null) ??
	classProperty.GetDbType() ??
	value?.GetType()?.GetDbType() ??
        classProperty != null ? clientTypeToDbTypeResolver.Resolve(classProperty.PropertyInfo.PropertyType) : null;

@@ -1547,6 +1547,17 @@ internal static Expression ConvertExpressionToClassHandlerSetExpression<TResult>
return Expression.Call(parameterVariableExpression, GetDbParameterValueSetMethod(), expression);
}

private static DbType? GetDbType(ClassProperty classProperty, Type dbFieldType)
Copy link
Owner

Choose a reason for hiding this comment

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

As part of our coding standard, you might notice that we are always doing a "new line" per argument.

private static DbType? GetDbType(ClassProperty classProperty,
      Type dbFieldType)
{
     ...
}

But I am happy that you are very engage here, I know that next time, you will be one of my biggest contributor and/or active collaborator. Thanks as always 😺

@mikependon
Copy link
Owner

I just finished the review for this and I will do the merge now 😺 . Though it is up to you if you would like to make an additional push on the minor comments I made, but the logic is now okay and reviewed.

Thank you always and please continue to do and maturize this library 🚀

@mikependon mikependon merged commit 8ea31c0 into master Jan 2, 2021
mikependon added a commit that referenced this pull request Jan 4, 2021
Follow the #690 review suggestion to make adjustments
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.

2 participants