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

Enum: writing to db fails, when global-option is automatic or db-field is primary-key #1100

Closed
Garios opened this issue Oct 17, 2022 · 2 comments
Assignees
Labels
bug Something isn't working fixed The bug, issue, incident has been fixed. priority Top priority feature or things to do

Comments

@Garios
Copy link

Garios commented Oct 17, 2022

Problem

I have a table with a primary-key ID [int]. The corresponding csharp class has a field ID, which is an enum [EnumTest:int]. If I make an insert on this table, then I get the exception "Compiler.Entity/Object.Property: Failed to automatically convert the value expression..."

The problem seems to be in Compiler.cs. In cases of Global-Option "Automatic" or when db-field is a primary-key it uses the "auto-conversion-handling", which doesn't cover enums. In this code-area it throws the exception. The code-block after would handle the enum-conversion, but to late:

Origin Code: Compiler.cs

internal static Expression GetEntityInstancePropertyValueExpression(Expression entityInstanceExpression, ClassProperty classProperty, DbField dbField)
{
	var expression = (Expression)Expression.Property(entityInstanceExpression, classProperty.PropertyInfo);

	// Target type
	var handlerInstance = classProperty.GetPropertyHandler() ?? PropertyHandlerCache.Get<object>(dbField.Type.GetUnderlyingType());
	var targetType = GetPropertyHandlerSetParameter(handlerInstance)?.ParameterType ?? dbField.Type;

	// Auto-conversion Handling
	if (GlobalConfiguration.Options.ConversionType == ConversionType.Automatic || dbField?.IsPrimary == true || dbField?.IsIdentity == true)
	{
		try
		{
//THIS LINE FAILS
			expression = ConvertExpressionWithAutomaticConversion(expression, targetType?.GetUnderlyingType());
		}
		catch (Exception ex)
		{
			throw new InvalidOperationException($"Compiler.Entity/Object.Property: Failed to automatically convert the value expression for " +
				$"property '{classProperty.GetMappedName()} ({classProperty.PropertyInfo.PropertyType.FullName})'. {classProperty}", ex);
		}
	}

	/*
		* Note: The other data provider can coerce the Enum into its destination data type in the DB by default,
		*       except for PostgreSQL. The code written below is only to address the issue for this specific provider.
		*/

	// Enum Handling
	if (classProperty.PropertyInfo.PropertyType.GetUnderlyingType().IsEnum == true)
	{
		try
		{
			if (!IsPostgreSqlUserDefined(dbField))
			{
				var dbType = classProperty.GetDbType() ?? classProperty.PropertyInfo.PropertyType.GetUnderlyingType().GetDbType();
				var toType = dbType.HasValue ? new DbTypeToClientTypeResolver().Resolve(dbType.Value) : targetType?.GetUnderlyingType();
				expression = ConvertEnumExpressionToTypeExpression(expression, toType);
			}
		}
		catch (Exception ex)
		{
			throw new InvalidOperationException($"Compiler.Entity/Object.Property: Failed to convert the value expression from " +
				$"enumeration '{classProperty.PropertyInfo.PropertyType.FullName}' to type '{targetType?.GetUnderlyingType()}'. {classProperty}", ex);
		}
	}

	// Property Handler
	try
	{
		expression = ConvertExpressionToPropertyHandlerSetExpression(
			expression, null, classProperty, dbField?.Type.GetUnderlyingType());
	}
	catch (Exception ex)
	{
		throw new InvalidOperationException($"Compiler.Entity/Object.Property: Failed to convert the value expression for property handler '{handlerInstance?.GetType()}'. " +
			$"{classProperty}", ex);
	}

	// Return the Value
	return ConvertExpressionToTypeExpression(expression, StaticType.Object);
}

Possible fix: Compiler.cs
I think it's better to check for enum before doing auto-conversion.

internal static Expression GetEntityInstancePropertyValueExpression(Expression entityInstanceExpression, ClassProperty classProperty, DbField dbField)
{
	var expression = (Expression)Expression.Property(entityInstanceExpression, classProperty.PropertyInfo);

	// Target type
	var handlerInstance = classProperty.GetPropertyHandler() ?? PropertyHandlerCache.Get<object>(dbField.Type.GetUnderlyingType());
	var targetType = GetPropertyHandlerSetParameter(handlerInstance)?.ParameterType ?? dbField.Type;


	/*
		* Note: The other data provider can coerce the Enum into its destination data type in the DB by default,
		*       except for PostgreSQL. The code written below is only to address the issue for this specific provider.
		*/

	// Enum Handling
	if (classProperty.PropertyInfo.PropertyType.GetUnderlyingType().IsEnum == true &&  !IsPostgreSqlUserDefined(dbField))
	{
		try
		{
				var dbType = classProperty.GetDbType() ?? classProperty.PropertyInfo.PropertyType.GetUnderlyingType().GetDbType();
				var toType = dbType.HasValue ? new DbTypeToClientTypeResolver().Resolve(dbType.Value) : targetType?.GetUnderlyingType();
				expression = ConvertEnumExpressionToTypeExpression(expression, toType);
		}
		catch (Exception ex)
		{
			throw new InvalidOperationException($"Compiler.Entity/Object.Property: Failed to convert the value expression from " +
				$"enumeration '{classProperty.PropertyInfo.PropertyType.FullName}' to type '{targetType?.GetUnderlyingType()}'. {classProperty}", ex);
		}
	}
	else if (GlobalConfiguration.Options.ConversionType == ConversionType.Automatic || dbField?.IsPrimary == true || dbField?.IsIdentity == true)
	{
		// Auto-conversion Handling
		try
		{
			expression = ConvertExpressionWithAutomaticConversion(expression, targetType?.GetUnderlyingType());
		}
		catch (Exception ex)
		{
			throw new InvalidOperationException($"Compiler.Entity/Object.Property: Failed to automatically convert the value expression for " +
				$"property '{classProperty.GetMappedName()} ({classProperty.PropertyInfo.PropertyType.FullName})'. {classProperty}", ex);
		}
	}

	// Property Handler
	try
	{
		expression = ConvertExpressionToPropertyHandlerSetExpression(
			expression, null, classProperty, dbField?.Type.GetUnderlyingType());
	}
	catch (Exception ex)
	{
		throw new InvalidOperationException($"Compiler.Entity/Object.Property: Failed to convert the value expression for property handler '{handlerInstance?.GetType()}'. " +
			$"{classProperty}", ex);
	}

	// Return the Value
	return ConvertExpressionToTypeExpression(expression, StaticType.Object);
}
@Garios Garios added the bug Something isn't working label Oct 17, 2022
@mikependon mikependon added the priority Top priority feature or things to do label Oct 19, 2022
@mikependon mikependon pinned this issue Oct 21, 2022
@mikependon
Copy link
Owner

Wierd! Pretty sure this has been working in the past, but someway along the road, this bug has been introduced and is not captured by the Integration Test. FYI: As of writing this, this error is also happening even on a simple Automatic conversion use-case of enum.

mikependon added a commit that referenced this issue Oct 22, 2022
mikependon added a commit that referenced this issue Oct 22, 2022
@mikependon mikependon unpinned this issue Oct 22, 2022
@mikependon mikependon added the fixed The bug, issue, incident has been fixed. label Oct 22, 2022
@mikependon
Copy link
Owner

The fixes to this issue is available on the next version > RepoDB v1.13.0-alpha2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working fixed The bug, issue, incident has been fixed. priority Top priority feature or things to do
Projects
None yet
Development

No branches or pull requests

2 participants