-
Notifications
You must be signed in to change notification settings - Fork 53
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
Models containing enum values throw Can't write CLR type #105
Comments
Similar issue in EF Core #489 |
Same problem here. EF6.Npgsql 3.2 and Npgsql 4.0.2. It worked fine in 3.2.7. |
I can second this, after been upgrading to newest ef6 and npgsql We map enums to int2, int4 or int8 depending on usage and type (for example enum flags for up to 64 values in combination) |
Thanks to everyone for reporting... @rwasef1830 if you have any free time to check this out that would be great. If not I'll try to take a look at this as soon as I can (hopefully this weekend). We definitely shouldn't have this regression. |
I took a quick look at this, the problem seems to be in the Z.EntityFramework.Extensions nuget package which adds the BulkInsert method used in the repro project. When I removed it and changed the code to a standard entity framework "add to context and save changes" code, it worked completely fine. So there appears to be no regression in the EF6 driver itself. My guess is that the library does some low level manipulation to do its bulk insert behavior and somehow it is not playing well with recent changes in Npgsql but it is very hard to debug the external NuGet package as it is actually a trial of a closed source package and the binaries are obfuscated. To other people having the same problem, please provide example/repro code. |
Here's my repo that reproduces the problem. https://github.com/CoderDennis/NpgsqlIssue105 I've got an entity with a compound key of a Guid and the Enum type. The error appears when executing I've run the same code against a Sql Server database and it executes without the error. |
@roji It seems to be a general issue in Npgsql, not the EF6 driver. What seems to be happening is that EF6 is passing the enum value as-is in the DbParameter (with NpgsqlDbType of Int32) to the generated DbCommand, and then in I'm not sure what is the proper 'enums as integers' code flow in Npgsql 4 but it would seem the fix is to try to cast the value to the handler type and throwing if it fails instead of just doing a type check in the generated handler lambda, and then having the rest of the handler code operate on the casted value instead of the original. |
Oh, you're saying that the 3.2 implementation allowed enums to be sent with |
@roji I can confirm, 3.2 seemed to take inbound enum types and perform an appropriate conversion. The issue seems to creep in when the enum is utilised in the query itself. I am able to successfully insert utilising the enum but if utilising an IQueryable or join on the enum type then the conversion fails and the CLR type error is thrown. Adding an explicit (int) conversion around the type alongside converting any incoming value to int resolves the issue. @roji slightly related - elmah/PgsqlErrorLog@09a7f92#diff-4a67f303004bfa29b7c780afea2b0c79 4.0 appears to cause issues when retrieving uuid columns. From the looks of it all of these are related to the notion of a string-convertible object from the db. |
I'm really having trouble. Has anyone managed to solve it? |
Do you have any predictions for the correction? |
Just revert back to 3.2.7, unless there is a specific feature from 4 that you really need |
Hi, any update on that? We use some third-party nuget which works as expected and we like its functionality. But this nuget uses calls like this many times: token = await context.Tokens.FindAsync(key, tokenType); where tokenType is enumerator |
Also discovered this bug after upgrading from 3.2.7. Hoped to get improved performance (with Postgres 11.2) but had to revert Npgsql update. |
I've been preoccupied lately to look at this, last time I checked it was a problem in Npgsql itself (something that changed there), I'll do a deep dive once again and see if there's a way to solve it when I get some time. |
@roji Did you manage to take a look at this with "regression" in Npgsql? |
@rwasef1830 re-reading this again... Are we simply missing the option for the int handler (and short and long) to accept an enum? If so, that shouldn't be too hard to do. However, this would depend on EF6 setting DbType.Integer (or NpgsqlDbType.Int) - I don't know enough about it. Can you please confirm? |
@roji Yes, the reason for the exception is that the method generated by This part is what causes the exception: https://github.com/npgsql/npgsql/blob/f52e1a5d9c189392f1757d0845a992d2bef3d11e/src/Npgsql/TypeHandling/NpgsqlTypeHandler%60.cs#L222 The solution would be to check if the type is an enum and if true to get its underlying type and then continue the check as normal. |
Opened npgsql/npgsql#2435 to track in Npgsql. |
It is possible to fix this in the EF6 driver without modifying Npgsql. I will implement a workaround. |
@roji This is fixed, you may want to roll out a new release. @haharoi @jbrezina @risulo @viniciusverasdossantos @CoderDennis class EnumToIntegerInterceptor : DbCommandInterceptor
{
public override void NonQueryExecuting(
DbCommand command,
DbCommandInterceptionContext<int> interceptionContext)
{
ConvertAllEnumsToIntegers(command.Parameters);
}
public override void ReaderExecuting(
DbCommand command,
DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
ConvertAllEnumsToIntegers(command.Parameters);
}
public override void ScalarExecuting(
DbCommand command,
DbCommandInterceptionContext<object> interceptionContext)
{
ConvertAllEnumsToIntegers(command.Parameters);
}
public override void ReaderExecuted(
DbCommand command,
DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
}
public override void ScalarExecuted(
DbCommand command,
DbCommandInterceptionContext<object> interceptionContext)
{
}
static void ConvertAllEnumsToIntegers(DbParameterCollection parameters)
{
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
foreach (DbParameter parameter in parameters)
{
if (parameter.Value == null)
{
return;
}
var parameterValueObjectType = parameter.Value.GetType();
if (!parameterValueObjectType.IsEnum)
{
continue;
}
var underlyingType = Enum.GetUnderlyingType(parameterValueObjectType);
parameter.Value = Convert.ChangeType(parameter.Value, underlyingType);
}
}
} |
Thanks a lot! |
Any tentative date of the release with the fix? |
Version 3.2.1 of the provider has just been released with this fix. |
I get the exception while trying to write to DB any data containing enums mapped to DB as ints (C# classes use enums in model classes and DB use INTEGER)
Can't write CLR type ReportServerORM.Model.TransactionCodeState with handler type Int32Handler
https://github.com/purple-technology/EFE-issue
EntityFramework\update-database -ProjectName TestingORM -StartUpProjectName TestingORM -Verbose
The text was updated successfully, but these errors were encountered: