InvalidCastException from property getter when a column is a nullable enum

Posts   
 
    
Posts: 98
Joined: 10-Nov-2006
# Posted on: 08-Sep-2010 22:54:12   

Observed with v 3.0 (September 8th, 2010)

I have an enum in my code like this:

public enum OpTransactionType : byte { X= 1, Y = 2 }

I have a column in my table that holds one of these enums. It's defined as a (tinyint NULL)

In the designer, I changed the type of the column from System.Byte to OPTransactionType using the built in enum support (no custom converter). This all worked fine.

But, the generated code for this property looks like this:


/// <summary> The OpTransactionType property of the Entity SaleView<br/><br/></summary>
        /// <remarks>Mapped on  view field: "ap_SaleView"."OpTransactionType"<br/>
        /// View field type characteristics (type, precision, scale, length): TinyInt, 3, 0, 0<br/>
        /// View field behavior characteristics (is nullable, is PK, is identity): true, false, false</remarks>
        public virtual Nullable<Auctionpay.Aesop.LLBLGenTypes.OpTransactionType> OpTransactionType
        {
            get { return (Nullable<Auctionpay.Aesop.LLBLGenTypes.OpTransactionType>)GetValue((int)SaleViewFieldIndex.OpTransactionType, false); }
            set { SetValue((int)SaleViewFieldIndex.OpTransactionType, value, true); }
        }


The problem is that this code throws a System.InvalidCastException when the getter is called. Here's the issue: the GetValue call returns an object that is a boxed byte. And C# will not let you convert that directly into a nullable enum.

So, I think that code similar to the following needs to be generated (note the new cast to byte? )

get { return (Nullable<Auctionpay.Aesop.LLBLGenTypes.OpTransactionType>)(byte?)GetValue((int)SaleViewFieldIndex.OpTransactionType, false); }

Thanks,

Wesley

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 09-Sep-2010 08:48:41   

Reproduced. We are looking into it.

David Elizondo | LLBLGen Support Team
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 09-Sep-2010 10:08:33   

It should be converted to the Enum internally already so the cast error shouldn't happen. The problem is in the datareader consumer: it checks for 'enum' but of course checking on the flag 'IsEnum' doesn't work if the type is a nullable<T>. Working on fix.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 09-Sep-2010 11:01:15   

Fixed. See attached dll.

Frans Bouma | Lead developer LLBLGen Pro
Dja
User
Posts: 29
Joined: 22-Jul-2010
# Posted on: 21-Feb-2011 11:23:29   

Hi. I have the same problem. I have an enum that looks like this:

public enum PersonSubType : int
    {
        Civilni = 1,
        Ostali = 3,
        Vojni = 2
    }

And a property which return type is set to be this enum through LLBL designer, and points to a column in database which is type of int. The property looks like this:

/// <summary> The SubType property of the Entity Person<br/><br/></summary>
        /// <remarks>Mapped on  table field: "PD_Person"."PD_PersonSubTypeId"<br/>
        /// Table field type characteristics (type, precision, scale, length): Int, 10, 0, 0<br/>
        /// Table field behavior characteristics (is nullable, is PK, is identity): true, false, false</remarks>
        public virtual Nullable<EnumTypes.PersonSubType> SubType
        {
            get { return (Nullable<EnumTypes.PersonSubType>)GetValue((int)PersonFieldIndex.SubType, false); }
            set { SetValue((int)PersonFieldIndex.SubType, value); }
        }

Property throws InvalidCastException when I try to fetch entity which has a non null value for this column in the database. I've tried the dll, that was previously attached but it still doesn't work.

Can you help me?

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 21-Feb-2011 14:29:49   

Did you follow this thread? Have you tried the attached fix? Does the problem still exist?

Dja
User
Posts: 29
Joined: 22-Jul-2010
# Posted on: 21-Feb-2011 15:29:02   

Yes. I've tried the fix, and the problem remains. But the strange thing is that when I import existing LLBL projects in the solution, and reference them, instead of referencing dlls, it works ok, and the property doesn't throw the exception. It works like that, but I would still like to reference dlls, or at least, I would like to know the reason for this. I don't get it... O_o

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 21-Feb-2011 15:33:53   

The only explanation is that the un-fixed dll was still referenced by the compiled projects.

So make sure the compiled projects (dlls) reference the fixed ORMSupportClasses dll.

Dja
User
Posts: 29
Joined: 22-Jul-2010
# Posted on: 21-Feb-2011 15:39:09   

Hm, that's strange. I downloaded source same time I downloaded libs. I'll try with the latest versions of dlls. I'll compare when I get it. Tnx.

Dja
User
Posts: 29
Joined: 22-Jul-2010
# Posted on: 09-Mar-2011 13:57:43   

It works fine after I switched to v3.1. simple_smile

Thanks.

dvdwouwe
User
Posts: 59
Joined: 24-Jul-2009
# Posted on: 13-Mar-2012 12:05:06   

Hi all,

I have the same problem. Version used: v3.1 Final (February 22nd, 2012)

I added multiple type shortcut definitions in my project. (see attachment) One of these shortcuts is Gender, which is an enum.

I also added the stored procedure call SpAddIntegrationNonActiveRequest (see attachment), which uses the type Gender for the parameter Gender. As you can see, this is an optional parameter, with direction InputOutput.

The generated code of this stored procedure call is:


        public static int SpAddIntegrationNonActiveRequest(System.DateTime startDate, KSZUtils.Sector sectorID, System.String userRequested, ref System.String iNSZ, ref System.String lastName, ref System.String firstName, ref System.String birthDate, ref Nullable<Constructiv.DataManagement.CrossDB.KSZServices.API.I.GenderEnum> gender, ref System.Int64 stgPersonID, ref Nullable<System.Int64> synergyID, ref System.Int64 integrationNonActiveRequestID, ref System.String errorInfo, IDataAccessCore dataAccessProvider)
        {
            using(StoredProcedureCall call = CreateSpAddIntegrationNonActiveRequestCall(dataAccessProvider, startDate, sectorID, userRequested, iNSZ, lastName, firstName, birthDate, gender, stgPersonID, synergyID, integrationNonActiveRequestID, errorInfo))
            {
                int toReturn = call.Call();
                iNSZ = call.GetParameterValue<System.String>(0);
                lastName = call.GetParameterValue<System.String>(1);
                firstName = call.GetParameterValue<System.String>(2);
                birthDate = call.GetParameterValue<System.String>(3);
                gender = call.GetParameterValue<Nullable<Constructiv.DataManagement.CrossDB.KSZServices.API.I.GenderEnum>>(4);
                stgPersonID = call.GetParameterValue<System.Int64>(7);
                synergyID = call.GetParameterValue<Nullable<System.Int64>>(8);
                integrationNonActiveRequestID = call.GetParameterValue<System.Int64>(9);
                errorInfo = call.GetParameterValue<System.String>(11);
                return toReturn;
            }
        }

The System.InvalidCastException happens here:


gender = call.GetParameterValue<Nullable<Constructiv.DataManagement.CrossDB.KSZServices.API.I.GenderEnum>>(4);

This happens although the value of this parameter is valid.

When modifying the parameter to be required and not optional (and thus not Nullable), there seems to be no problem.

Attachments
Filename File size Added on Approval
TypeShortCutEditor.png 42,141 13-Mar-2012 12:05.46 Approved
spAddIntegrationNonActiveRequest.png 49,145 13-Mar-2012 12:05.53 Approved
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 14-Mar-2012 11:15:59   

In the february 22nd build a fix for this was added, however it seems it doesn't work for enums. It's a bit problematic, as several casts in chain fail in some situation, so we'll look into why this is.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 15-Mar-2012 11:02:33   

As you didn't give a stacktrace nor a glimpse of info which database you're using, we'll assume sqlserver. If we can't reproduce it with that, we'll have to close this till you give more information.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 15-Mar-2012 11:36:02   

I can reproduce it on sqlserver.

It actually crashes on: return (TValue)parameterValue; where TValue is the Nullable<T> and parameterValue the int value. What's so stupid is that if I type the exact same expression in the debugger immediate window it works, but not in code. When I do: Convert.ChangeType(parameterValue, typeof(TValue)) in the immediate window it gives the cast exception.

Nullable<T> is seriously broken. disappointed

Frans Bouma | Lead developer LLBLGen Pro
dvdwouwe
User
Posts: 59
Joined: 24-Jul-2009
# Posted on: 15-Mar-2012 11:49:35   

Sorry, totally forgot to add that information disappointed . The database used, is indeed SQL Server (2008, v10.0.5500).

Stacktrace:


   at SD.LLBLGen.Pro.ORMSupportClasses.StoredProcedureCall.GetParameterValue[TValue](Int32 parameterIndex)
   at CrossDB.Data.DatabaseSpecific.ActionProcedures.SpAddIntegrationNonActiveRequest(DateTime startDate, Sector sectorID, String userRequested, String& iNSZ, String& lastName, String& firstName, String& birthDate, Nullable`1& gender, Int64& stgPersonID, Nullable`1& synergyID, Int64& integrationNonActiveRequestID, String& errorInfo, IDataAccessCore dataAccessProvider) in C:\Development\CrossDB\CrossDB_OUT\Services\DALs\CrossDB.Data\DatabaseSpecific\ActionProcedures.cs:line 164
   at KSZServices.Utils.TransactionalProcedures.SpAddIntegrationNonActiveRequest(DateTime startDate, Sector sector, String user, String& normalizedInsz, String& lastName, String& firstName, String& birthDate, Nullable`1& gender, Int64& stgPersonID, Nullable`1& synergyId, Int64& integrationNonActiveRequestID, DataAccessAdapter adapter) in C:\Development\CrossDB\CrossDB_OUT\Services\KSZServices\Utils\TransactionalProcedures.cs:line 920
   at KSZServices.ServiceImplementations.PersonDao.RegisterPersonIntegrationRequestInternally(Sector sector, Person person, Int64& stgPersonID) in C:\Development\CrossDB\CrossDB_OUT\Services\KSZServices\ServiceImplementations\PersonDao.cs:line 121
   at KSZServices.ServiceImplementations.PersonDao.RequestIntegrationForPerson(Sector sector, Person person) in C:\Development\CrossDB\CrossDB_OUT\Services\KSZServices\ServiceImplementations\PersonDao.cs:line 99
   at SyncInvokeRequestIntegrationForPerson(Object , Object[] , Object[] )
   at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
   at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 15-Mar-2012 12:07:14   

Fixed in attached dll.

Please next time give more information, as you didn't give vital information about which database you're using, which is kind of essential with respect to stored procs. Thanks. simple_smile

Attachments
Filename File size Added on Approval
SD.LLBLGen.Pro.ORMSupportClasses.NET20.zip 274,656 15-Mar-2012 12:07.23 Approved
Frans Bouma | Lead developer LLBLGen Pro
dvdwouwe
User
Posts: 59
Joined: 24-Jul-2009
# Posted on: 15-Mar-2012 13:28:48   

Ok, it works fine now! Thanks! simple_smile