question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Enums: error when dbValue doesn't exist in Enum-Values

See original GitHub issue

Bug Description

I think #956 has the same problem.

If I have values in table, which doesn’t exist in the given Enum, then I get the following error. I don’t use string-values. I use byte, short, int, long.

Exception Message:

System.ArgumentNullException: 'Value cannot be null. Arg_ParamName_Name'

Model:

    public enum TestEnum : int
    {
        None = 0,
        Type1 = 1
    }
    public class TestTable
    {
        public long ID { get; set; }
        public TestEnum TestType { get; set; }
    }

Compiler creates:

new TestTable() 
{
    ID = reader.GetInt64(0),
    TestEnum = Convert(Parse(TestEnum, GetName(TestEnum, Convert(reader.GetInt32(1), Object)), True), TestEnum)
}

Assume reader.GetInt32(1) returns "4". But "4" doesn't exist in TestEnum. Then GetName returns "null". Parse throws the error...

Expected Behaviour return default(TestEnum)

Possible Solution

long dbValue = 4; //note, in this case the db-type differs from the corresponding enum-type int
var baseType = typeof(TestEnum).GetEnumUnderlyingType();

object convertedDbValue = dbValue;
if (baseType != dbValue.GetType()) //if dbValue-Type differs from underlying enum-type
	convertedDbValue = Convert.ChangeType(dbValue, baseType); //ex. long to int

object result;
if (Enum.IsDefined(typeof(TestEnum), convertedDbValue))
	result = Enum.ToObject(typeof(TestEnum), dbValue);
else
	result = default(TestEnum);
return result;

Solution translated to Compiler Replace the following Method in Compiler.cs:

(I never used Expression before!)

internal static Expression ConvertExpressionToEnumExpressionForNonString(Expression expression, Type toEnumType)
{
	Type baseType = toEnumType.GetEnumUnderlyingType();
	if (baseType != expression.Type)
	{
		var convertMethod = StaticType.Convert.GetMethod("ChangeType", new[] { StaticType.Object, StaticType.Type });
		var convertParameters = new Expression[]
		{
			Expression.Convert(expression, StaticType.Object),
			Expression.Constant(baseType)
		};
		expression = Expression.Call(convertMethod, convertParameters);
	}
	else
		expression = Expression.Convert(expression, StaticType.Object);

	var isDefinedMethod = StaticType.Enum.GetMethod("IsDefined", new[] { StaticType.Type, StaticType.Object });
	var isDefinedParameters = new Expression[]
	{
			Expression.Constant(toEnumType),
			expression
	};            
	var isDefinedExpression = Expression.Call(isDefinedMethod, isDefinedParameters);

	var toObjectMethod = StaticType.Enum.GetMethod("ToObject", new[] { StaticType.Type, StaticType.Object });
	var toObjectParameters = new Expression[]
	{
			Expression.Constant(toEnumType),
			expression
	};
	var toObjectExpression = Expression.Call(toObjectMethod, toObjectParameters);

	var defaultExpression = Expression.Convert(Expression.Default(toEnumType), StaticType.Object);

	return Expression.Condition(isDefinedExpression, toObjectExpression, defaultExpression);
}

Library Version: Current master.

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:16 (11 by maintainers)

github_iconTop GitHub Comments

1reaction
mikependoncommented, Oct 25, 2022

Oh. Looks like then, we might have built the package from the master before the actual fixes/code has been merged then. Anyway, we can issue a new alpha, or maybe promote to a beta so we can start work on our documentations. We will notify you ASAP once the new package has been pushed.

1reaction
Garioscommented, Oct 24, 2022

Using GlobalConfiguration.Options.EnumHandling

public enum EnumHandling
{
    ThrowError = 0, //Default
    UseDefault = 1,
    Cast = 2
}

internal static Expression ConvertExpressionToEnumExpressionForNonString(Expression expression, Type toEnumType)
{
    EnumHandling handler = EnumHandling.ThrowError; //GlobalConfiguration.Options.EnumHandling

    if (handler == EnumHandling.Cast)
        return Expression.Convert(expression, toEnumType);



    Type baseType = toEnumType.GetEnumUnderlyingType();
    if (baseType != expression.Type)
    {
        var convertMethod = StaticType.Convert.GetMethod("ChangeType", new[] { StaticType.Object, StaticType.Type });
        var convertParameters = new Expression[]
        {
            Expression.Convert(expression, StaticType.Object),
            Expression.Constant(baseType)
        };
        expression = Expression.Call(convertMethod, convertParameters);
    }
    else
        expression = Expression.Convert(expression, StaticType.Object);

    var isDefinedMethod = StaticType.Enum.GetMethod("IsDefined", new[] { StaticType.Type, StaticType.Object });
    var isDefinedParameters = new Expression[]
    {
            Expression.Constant(toEnumType),
            expression
    };
    var isDefinedExpression = Expression.Call(isDefinedMethod, isDefinedParameters);


    Expression notDefinedExpression;
    if (handler == EnumHandling.UseDefault)
        notDefinedExpression = Expression.Convert(Expression.Default(toEnumType), StaticType.Object);
    else
    {
        var stringConcat = StaticType.String.GetMethod("Concat", new[] { typeof(string), typeof(string) });
        var errorMessage = Expression.Call(stringConcat, Expression.Constant(toEnumType.Name + " doesn't define enum-value "), Expression.Call(expression, StaticType.Object.GetMethod("ToString")));

        var argumentExceptionConstructor = typeof(ArgumentException).GetConstructor(new[] { StaticType.String });
        var throwException = Expression.Throw(Expression.New(argumentExceptionConstructor, errorMessage), StaticType.Object);

        notDefinedExpression = throwException;
    }


    var toObjectMethod = StaticType.Enum.GetMethod("ToObject", new[] { StaticType.Type, StaticType.Object });
    var toObjectParameters = new Expression[]
    {
            Expression.Constant(toEnumType),
            expression
    };
    var toObjectExpression = Expression.Call(toObjectMethod, toObjectParameters);

    return Expression.Condition(isDefinedExpression, toObjectExpression, notDefinedExpression);
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Enum value '' is invalid for type > 'EnumType' and cannot ...
Yes, that particular enum value does not exist within the C# Enum definition because the PropertyId's are dynamic and may be added to...
Read more >
Enum values do not map to underlying raw values #9877
Bug description When using prisma.$queryRaw against enum values, I cannot cast the database enum type to the client enum type.
Read more >
JsonSerializer does not enforce enum values · Issue #42093
If I have a class with an enum in it, and I take it as an argument to a controller's endpoint, the enum...
Read more >
MySQL 8.0 Reference Manual :: 11.3.5 The ENUM Type
An ENUM is a string object with a value chosen from a list of permitted values that are enumerated explicitly in the column...
Read more >
Check if an Enum Value Exists in Java
We can use the data in an incoming request and find that enum. For example, we can map web error 400 to BAD_REQUEST....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found